投げ銭

★当サイトへの投げ銭(PayPal)★

LINK


(無償、寄付歓迎) logo
世界中で使われるISO標準オフィスソフト(MSオフィス互換)

★LibreOfficeの導入事例★
詳細について

人気の投稿(1ヶ月間)

Ad

Ad

投げ銭

★当サイトへの投げ銭(PayPal)★

2020年2月29日土曜日

【Linux CentOS 7】grep、sedの正規表現でワイルドカードみたいなパターンを作る(最短マッチと、最長マッチの違い)

正規表現の最短一致の方法


次のような内容のテキストファイルがあるとする。
(セミコロンで項が区切られている。)
abc-1234; def-1234; abc-5678; def-5678; abc-9012; def-9012;
このうち、abcから始まる項目だけgrepで検索したいとする。



× ダメな方法
次のようにしてもうまくいかない。(おそらく最初に思いつく表現)

$ grep "abc.*;" testfile.txt
abc-1234; def-1234; abc-5678; def-5678; abc-9012; def-9012;

しかし、赤で示されているようにすべてが検索されてしまう。

これは、正規表現の「.*」ワイルドカード部分が、途中に何度も出てくる「;」まで含んで検索してしまうためである。
その結果、正規表現中の「;」は、テキストファイル中の一番最後の「;」とようやくマッチすることになる。
これは最長一致と呼ばれる。


そうではなくて、ターゲット文字列にabcが登場した後に最初に出て来る「;」とマッチするようにして、セミコロンで区切られた各項ごとに照合したい。
この場合は最短一致と呼ばれる。


○次のようにすれば最短一致となる。

$ grep "abc[^;]*;" testfile.txt
abc-1234; def-1234; abc-5678; def-5678; abc-9012; def-9012;

「;」でデータ項目が区切られているのだから、「;」はデータ中で区切るという特別な意味を持っている。
この場合は「.*」の代わりに、「 [^;]* 」を用いることがポイントである。
「.*」の「.」は任意の文字を表すので、区切りであろうが関係なくマッチして、最長一致になってしまったのだった。
そうならないように、ここでは「 [^;] 」を用いている。
「 [^;] 」は「;」以外の任意の文字を表す。

そして「 [^;]* 」は、「;」以外の任意の文字の繰り返しを表す。
だから、検索中に項目の区切り「;」がデータに登場すると、それはもはや「 [^;] 」にはマッチしなくなり、
正規表現中の最後の表現「;」に処理が移ることになる。

これによって、正規表現の三要素で構成されるパターン、
すなわち「abc」、「 [^;]* 」、「;」が順番にマッチしていき、
意図したように「abc」から始まってから最短で出て来る「;」で終わるパターンが検索できるようになる。



■同様に、sedでの置換も試してみる。

sedは指定したテキストファイル全体を、
正規表現で検索し、マッチした部分を指定した文字列に置換できる。

それには、次の構文を使う。

sed -e "s/検索用正規表現/文字列/g"

ここでは、検索でマッチした文字列を、「/**/」に置き換えたい。
「/**/」で使われている「/」「*」は制御記号と区別するために「\」でエスケープしなければならない。

では、ダメな方法から試してみる。


×ダメな方法(さきほどと同じように最長マッチしてしまう。)
$ sed -e "s/abc.*;/ \/*\*\//g" testfile.txt
 /**/
先程と同じようにテキストの全部にマッチしてしまい、全体が「/**/」で置換されてしまう。


○意図した動作をする方法(最短マッチ)

$ sed -e "s/abc[^;]*;/ \/*\*\//g" testfile.txt
 /**/ def-1234;  /**/ def-5678;  /**/ def-9012;
「abc」から始まってから最短で出て来る「;」で終わるパターンが検索されて、
個々が「/**/」に置換される。

投げ銭

★当サイトへの投げ銭(PayPal)★

Ad

Ad