sedとgrepで正規表現をお勉強しましょう
最初に正規表現をお勉強するには比較的メジャーなsedコマンドとgrepコマンドを使った方が良いかなと思いますのでこれらを利用して正規表現のお勉強をしましょう。
2つのコマンドはWindows10のWSL(Windows Subsystem for Linux)のubuntu(18.04)のものを使いますのでインストールして下さい。
Linuxを使用しますので文字コードはUTF-8、改行コードはLF(0x0a)になります。
ご自身でテキストファイルを作成するときはご注意下さい。
sedコマンドの文字列置換機能を利用します。
置換機能を用いることでどの部分がマッチしたかを確認(推測)できます。
主にこちらを使います。
grepコマンドは文字列を検索をするだけのときに使います。
sedのコマンドは下記のようになります。
sed -E 's/検索用正規表現/置換文字列/g' 置換対象ファイル名 -E 拡張正規表現を用います(TEditorMXと同様なものになります) s 文字列置換を行います g 検索してマッチした文字列すべてを置換します
grepのコマンドは下記のようになります。
grep -E '正規表現' 検索対象ファイル名 -E 拡張正規表現を用います(TEditorMXと同様なものになります)
項目
(1).(ピリオド)
(2)*
(3)+
(4)(pattern)
(5)x|y
(6){min,max}
(7)[xyz]
(8)^, $
(9)\d
(10)\s
(11)正規表現サンプル
(1).(ピリオド)
.(ピリオド)は改行コード以外の1文字とマッチします。
sed -E 's/./=/g' test_period_8.txt
置換前(test_period_8.txt)
a bc def あいうえお
置換後
= == === =====
置換文字列(=)の数を数えれば半角文字(アルファベット)とマルチバイト文字(ひらがな)に関係なく、各文字一つ一つと .(ピリオド)がマッチしていることが確認できると思います。
(2)*
前のパターンの0回以上の繰り返しにマッチします。0回以上なので空文字列ともマッチします。
空文字列とは各文字の左側※2にあると仮定している文字数0の実体のない文字列のことです。
「空文字列とマッチ」と表現されているときは文字の左側にあると仮定している文字数0の実体のない文字列とマッチしているということです。
- ※2
- 正確には文字の周りのあらゆるところにあるとされていますが処理の都合上、文字の左側にのみあるものと仮定しています...しているのではないかと思われます。
sed -E 's/.*/=/g' test_period_8.txt
置換前(test_period_8.txt)
a bc def あいうえお
置換後
= = = =
となります。ちょっと話が脱線しますが、これと同様のことをTEditorMXで実行すると結果が異なり以下のようになります。
== == == == =
これは『仕様の違い』または『解釈の違い』だと思います。
sedではマッチした文字列が行末まで行くと次の行から検索を開始するのだと思われます。
そのため置換文字列(=)が各行1つしかないのだと思われます。
それに対してTEditorMXはマッチした文字列が行末まで行ったとしても行末から検索を開始します。
そのため行末の空文字列とマッチするので置換文字列(=)が各行2つになります。
で、さらにTEditorMXでは5行目にも置換文字列(=)が1つあります。
これはファイルの最後にEOF(End Of File 0x1a)があるものとして処理しているためEOFの左側の空文字列とマッチして置換されるためです。
この辺の微妙な違いについては、どちらが良いかは使う人の好みかもしれません。
ちなみにTEditorMXでsedと同じような結果を得るには下記のようにすればOKです。
検索文字列
.*(\r\n)
\r\nは改行コードです。改行コードまで記述すれば1行全体を置換できます。
置換文字列
=\r\n または =$1
$1は後方参照です。 この場合は改行コードになります。
置換後
= = = =
(3)+
前のパターンの1回以上の繰り返しにマッチします。1回以上なので空文字列とはマッチしません。
sed -E 's/.+/=/g' test_period_8.txt
置換前(test_period_8.txt)
a bc def あいうえお
置換後
= = = =
となります。
(4)(pattern)
グルーピング。patternをひとまとまりの正規表現とします。
例えば (abc)+ とした場合には、1個以上の abc とマッチしますので、
置換前(test_group1_8.txt)
abc abcabc abcabcabc
の何れの abc にもマッチします。
sed -E 's/(abc)+/=/g' test_group1_8.txt
= = =
また、優先順位を替えるためにも使用できます。
置換前(test_group2_8.txt)
東京ドーム 東京タワー 東京駅 東京スカイツリー 東京都
の中から「東京スカイツリー」と「東京駅」を検索したい場合を考えます。
東京スカイツリー|駅
と記述してしまうと「東京スカイツリー」と「駅」にマッチして上手く検索できません。
そこでグルーピングを用いて、
東京(スカイツリー|駅)
と記述すると今度は「東京スカイツリー」と「東京駅」の両方を上手く検索することができます。
sed -E 's/東京(スカイツリー|駅)/=/g' test_group2_8.txt
東京ドーム 東京タワー = = 東京都
となります。
マッチした『東京駅』と『東京スカイツリー』が『=』に置換されました。
(5)x|y
正規表現 x または y にマッチします(OR)。
sed -E 's/def|jkl/=/g' test_or_8.txt
abc def ghi jkl mno
置換後
abc = ghi = mno
となります。
def と jkl にマッチしていますね。
(6){min,max}
直前の正規表現の指定回数(min以上、max以下)の繰り返しにマッチします。
{number} と指定するとnumber回ちょうどの繰り返しとマッチします。
sed -E 's/(abc){2,3}/=/g' test_repeat1_8.txt
abc abcabc abcabcabc abcabcabcabc
置換後
abc = = =abc
となります。2回、または3回のabcの繰り返しとマッチしていることが確認できました。
(7)[xyz]
キャラクタリスト。指定されたxyzの中の何れかにマッチします。
ハイフン(-)で範囲指定することも可能です。[0-9]と記述すると数字1文字にマッチしますし、[A-Za-z]と記述しますとアルファベットの1文字とマッチします。
もちろんマルチバイト文字も使えます。
否定
キャラクタリストの先頭に ^ を置くと否定になります。
例えば [^0-9] と記述しますと数字以外の文字とマッチしますし、[^A-Za-z]と記述しますとアルファベット以外の文字とマッチします。
sed -E 's/[0-5]/=/g' test_charlist_8.txt置換前(test_charlist_8.txt)
0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ぁあぃいぅうぇえぉお ががきぎぐけけげこご
置換後
======6789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ぁあぃいぅうぇえぉお ががきぎぐけけげこご
先頭行の0~5が = に置換されました。
(8)^, $
^ は行頭にマッチします。$ は改行コードの直前、改行コードが無いときは行末にマッチします。
テキストファイル(test_sample1_8.cpp)から行頭にHANDLEという文字列がある行をgrepコマンドを使って検索してみます。
grep ^HANDLE test_sample1_8.cpp
HANDLE OpenInFile( char *lpFileName, BOOL fInOutFile ) HANDLE OpenOutFile( char *lpFileName )
という結果になると思います。
また、行末が e; で終わっている行を検索すると、
grep 'e;$' test_sample1_8.cpp
HANDLE hOpenFile; HANDLE hOpenFile; int num, lp, size; DWORD readSize, writeSize; checkSum = (unsigned char)size; DWORD readSize, writeSize; HANDLE hInFile, hOutFile; DWORD readSize, writeSize; unsigned long line; fInOutFile = false; fInOutFile = true; fInOutFile = true; fError = true; fError = true; fError = true;
という結果になると思います。 全て行末が e; という文字で終わっていることが確認できますね。
(9)\d
アラビア数字[0-9]1文字とマッチします。
(10)\s
空白文字[ \f\n\r\t\v]とマッチします。
(11)正規表現サンプル
1.数値(整数)[+-]?\d+
(\+|-)?\d+
+10
-5
100
などの整数値にマッチします。
[+-]?\d+(\.\d*)?
(\+|-)?\d+(\.\d*)?
+10
-5
100
などの整数値の他に、
+98.6
-1988.35
2056.324
などの小数値にもマッチします。
\d{3}-\d{4}
123-4567
のような郵便番号にマッチします。
\d{4}/\d{1,2}/\d{1,2}
2019/1/10
1930/12/31
のような日付にマッチします。
0x[0-9a-fA-F]+
0x5f
0xab16
0xFFEE0099
のような16進数にマッチします。
^\s*$
空白行、または空白文字しか含まない行とマッチします。