TITLE:間違いだらけの正規表現講座 level 7
#contentsx
* れっつ練習! [#vdcb7bcb]
さて、駆け足でやってきましたが、第6回までの説明で、正規表現での検索の基本の部分は押さえたことになります。
次回からは、正規表現の真骨頂、正規表現を使った置換のやりかたを見ていきますが、
ここらで一旦おさらいを兼ねて、検索の練習をしてみましょう。
* おさらい [#baac8c4b]
まずは、今まで出てきたメタ文字をおさらいしましょう。
|メタ文字|意味|出てきた回|h
|.|任意の1文字にマッチ|[[第1回>正規表現講座/1]]|
|[abc]|[]内のどれか1文字にマッチ|[[第1回>正規表現講座/2]]|
|[a-z]|[]内のa~zにマッチ|[[第2回>正規表現講座/2]]|
|[^abc]|[]内以外の任意の1文字にマッチ|[[第2回>正規表現講座/2]]|
|*|直前の正規表現の、0回以上の繰り返し|[[第3回>正規表現講座/3]]|
|+|直前の正規表現の、1回以上の繰り返し|[[第3回>正規表現講座/3]]|
|?|直前の正規表現の、0回もしくは1回の繰り返し|[[第3回>正規表現講座/3]]|
|()|()内の正規表現を、まとめて1つの正規表現として扱う|[[第4回>正規表現講座/4]]|
|\t|タブ記号|[[第5回>正規表現講座/5]]|
|\r|改行記号 0D|[[第5回>正規表現講座/5]]|
|\n|改行記号 0A|[[第5回>正規表現講座/5]]|
|\|直後の記号をエスケープする|[[第5回>正規表現講座/5]]|
|^|先頭にマッチ|[[第6回>正規表現講座/6]]|
|$|末尾にマッチ|[[第6回>正規表現講座/6]]|
* レッツチャレンジ [#ted1c7d3]
では、例題です。試しに、HTMLのようなものの検索をしてみましょう。
正規表現テスターを立ち上げ、以下の文章をコピペして、チャレンジしてみてください。~
上手く行ったら、自分の使っているエディタに正規表現の機能があるかどうか調べ、
そのエディタでも試してみましょう。
なお、正規表現テスターでは、
-シングルラインモードON/OFF:『「.」が改行にもマッチする』(チェックでON)
-マルチラインモードON/OFF:『「^$」が各行毎にマッチする』(チェックでON)
-改行記号は \n
となっています。
* 例題 [#ra4e6e46]
#HTMLのようなもの。
#これはコメントです。
<html>
<a href="01234.html">電話番号#1="012-3456-7890"</a>
<a href="56789.html">電話番号#2="090-0000-0000"</a>
<a href="kenokeno.html">へもへも</a>
<a href="kenokeno.html">へもへもへも</a>
<a href="mononoke.html">ものへも
</a>
</html>
- 電話番号(012-3456-7890とか)にマッチする正規表現を書け。
- 数字で出来たファイル名だけ(01234.htmlとか)にマッチする正規表現を書け((ヒント:「.」はメタ文字です!))
- 「<a href="~">」の部分にマッチする正規表現を書け((ヒント:途中の空白が何文字か決まっていませんね))
- へも、の繰り返しで出来ている部分にマッチする正規表現を書け((ヒント:「へも」を単位とした繰り返しです))
- タグ(<と>で囲まれたもの)に全てマッチする正規表現を書け((ヒント:シングルラインモードは?))
- コメントっぽい行(最初の2行)にマッチする正規表現を書け((ヒント:行の頭が#で始まっていますね))
- 行内で完結しているリンク(<aで始まり/a>で終わる)にマッチする正規表現を書け((ヒント:シングルラインモードは?))
- 全てのリンクにマッチする正規表現を書け((ヒント:最後のリンクはどうしましょう))
* 欲張りなマッチと欲張りでないマッチ [#h8c05c43]
さて、最後の問題が厄介だったのではないでしょうか。
単純に「<a.*/a>」などとすると、最後のリンクは改行が混じっているので
マッチできませんね。
仕方ないので、シングルラインモード(「.」が改行にもマッチする)を
チェックして試してみると、今度は、4つのリンクが全部いっぺんにマッチして
しまった筈です。
これは、第3回でちらっと述べた、「最長一致の法則」、別名「欲張りなマッチ」
という仕様が関係しています。
「.*」は、マッチできる限り最長の文字列にマッチしようとします。
「.」が改行にマッチしない場合(シングルラインモードOFF)であれば、
「.*」は改行のところで有効範囲が切れるのですが、
「.」が改行にマッチするようにすると、
何行も何行も延々とマッチし続けてしまうのですね。
つまり、~
''『「<a」で始まって、改行を含む何文字かがあって、「/a>」で終わる最長の文字列』''~
を探してしまうわけで、途中に「<a」や「/a>」が含まれていても、
それは「.*」の一部分と考えられてしまうわけです。
このような場合に使うのが、「最短一致」です。
&color(Red){「*」「+」の後に「?」をつけると、その場合だけ、「*」「+」は、「可能な限り最短の文字列にマッチ」するようになります。};
シングルラインモードONの状態で、「<a.*?/a>」で検索して試してみてください。
今度は上手く行く筈です。
この場合、~
''『「<a」で始まって、改行を含む何文字かがあって、「/a>」で終わる最短の文字列』''~
を探すので、このような動作になります。
というわけで、メタ文字の一覧に追加です。~
こればかりは、実際に例題をやって悩んでみないと存在意味がわからないので、~
最後にもってきたのでした。
|メタ文字|意味|h
|*?|直前の正規表現の、0回以上の繰り返し(最短一致)|
|+?|直前の正規表現の、1回以上の繰り返し(最短一致)|
なお、「*」「+」だけでなく、量指定子と呼ばれる、繰り返しを指定する
メタ文字であれば、その後ろに「?」をつけることにより、最短一致に
することができます。
* ちょっと脱線 [#wa94b11e]
さて、本文中、いきなり「欲張り」とか言い出してふざけてると思ったのではないでしょうか。~
が、実は「欲張りなマッチ」「greedy match」という、正規表現上の専門用語なのです。~
他にも、「強欲なマッチ」「possessive match」なんてのもあります。
コンピュータの専門用語、特にUNIX系の用語って、プロセスを殺したり(kill)、
プロセスがゾンビ(zombie process)になったり、OSがあわてふためいたり(panic)、
茶目っ気のあるというか、コンピュータを擬人化したものが多いですね。
プログラムをしていると、そういう言葉を使うのは良く分かります。~
プログラミングというのは、無意識にコンピュータやプログラムの「気持ち」を想像して、~
「プログラムの立場に立って」ものを考えるからでしょうか。
開発の現場にいると、
この子があっちのサーバにリクエストを投げます。もしサーバがダンマリだったり
死んでたりしたら、仕方ないのでDBを見に行って別のサーバに投げなおします。
なんて発言は日常茶飯事、だれも気にせず使っていますが、
このプロセスがあっちのサーバにリクエストを送信します。もしサーバがレスポンスを
返さなかったり、サーバが起動していなかったりしたら、データベースを検索して、
別のサーバに送信しなおします。
というのが正しい日本語ですよね。
* ご指摘などはこちらへ [#kedca7c3]
#comment