* U K I Y A H O N P O *
Nel mezzo del cammin di nostra vita mi ritrovai per una selva oscura,
che la diritta via era smarrita.
リロード   新規 下位ページ作成 編集 凍結 差分 添付 コピー 名前変更   ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS
浮子屋商店もよろしく。

正規表現講座/7 のバックアップ(No.6)


れっつ練習!

さて、駆け足でやってきましたが、第6回までの説明で、正規表現での検索の基本の部分は押さえたことになります。

次回からは、正規表現の真骨頂、正規表現を使った置換のやりかたを見ていきますが、 ここらで一旦おさらいを兼ねて、検索の練習をしてみましょう。

おさらい

まずは、今まで出てきたメタ文字をおさらいしましょう。

メタ文字意味出てきた回
.任意の1文字にマッチ第1回
[abc][]内のどれか1文字にマッチ第1回
[a-z][]内のa~zにマッチ第2回
[^abc][]内以外の任意の1文字にマッチ第2回
*直前の正規表現の、0回以上の繰り返し第3回
+直前の正規表現の、1回以上の繰り返し第3回
?直前の正規表現の、0回もしくは1回の繰り返し第3回
()()内の正規表現を、まとめて1つの正規表現として扱う第4回
\tタブ記号第5回
\r改行記号 0D第5回
\n改行記号 0A第5回
\直後の記号をエスケープする第5回
^先頭にマッチ第6回
$末尾にマッチ第6回

レッツチャレンジ

では、例題です。試しに、HTMLのようなものの検索をしてみましょう。

正規表現テスターを立ち上げ、以下の文章をコピペして、チャレンジしてみてください。
上手く行ったら、自分の使っているエディタに正規表現の機能があるかどうか調べ、 そのエディタでも試してみましょう。

なお、正規表現テスターでは、

  • シングルラインモードON/OFF:『「.」が改行にもマッチする』(チェックでON)
  • マルチラインモードON/OFF:『「^$」が各行毎にマッチする』(チェックでON)
  • 改行記号は \n

となっています。

例題

#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とか)にマッチする正規表現を書け*1
  • 「<a href="~">」の部分にマッチする正規表現を書け*2
  • へも、の繰り返しで出来ている部分にマッチする正規表現を書け*3
  • タグ(<と>で囲まれたもの)に全てマッチする正規表現を書け*4
  • コメントっぽい行(最初の2行)にマッチする正規表現を書け*5
  • 行内で完結しているリンク(<aで始まり/a>で終わる)にマッチする正規表現を書け*6
  • 全てのリンクにマッチする正規表現を書け*7

欲張りなマッチと欲張りでないマッチ

さて、最後の問題が厄介だったのではないでしょうか。

単純に「<a.*/a>」などとすると、最後のリンクは改行が混じっているので マッチできませんね。

仕方ないので、シングルラインモード(「.」が改行にもマッチする)を チェックして試してみると、今度は、4つのリンクが全部いっぺんにマッチして しまった筈です。

これは、第3回でちらっと述べた、「最長一致の法則」、別名「欲張りなマッチ」 という仕様が関係しています。

「.*」は、マッチできる限り最長の文字列にマッチしようとします。

「.」が改行にマッチしない場合(シングルラインモードOFF)であれば、 「.*」は改行のところで有効範囲が切れるのですが、 「.」が改行にマッチするようにすると、 何行も何行も延々とマッチし続けてしまうのですね。

つまり、
『「<a」で始まって、改行を含む何文字かがあって、「/a>」で終わる最長の文字列』
を探してしまうわけで、途中に「<a」や「/a>」が含まれていても、 それは「.*」の一部分と考えられてしまうわけです。

このような場合に使うのが、「最短一致」です。

「*」「+」の後に「?」をつけると、その場合だけ、「*」「+」は、「可能な限り最短の文字列にマッチ」するようになります。

シングルラインモードONの状態で、「<a.*?/a>」で検索して試してみてください。 今度は上手く行く筈です。

この場合、
『「<a」で始まって、改行を含む何文字かがあって、「/a>」で終わる最短の文字列』
を探すので、このような動作になります。

というわけで、メタ文字の一覧に追加です。
こればかりは、実際に例題をやって悩んでみないと存在意味がわからないので、
最後にもってきたのでした。

メタ文字意味
*?直前の正規表現の、0回以上の繰り返し(最短一致)
+?直前の正規表現の、1回以上の繰り返し(最短一致)

なお、「*」「+」だけでなく、量指定子と呼ばれる、繰り返しを指定する メタ文字であれば、その後ろに「?」をつけることにより、最短一致に することができます。

ちょっと脱線

さて、本文中、いきなり「欲張り」とか言い出してふざけてると思ったのではないでしょうか。
が、実は「欲張りなマッチ」「greedy match」という、正規表現上の専門用語なのです。
他にも、「強欲なマッチ」「possessive match」なんてのもあります。

コンピュータの専門用語、特にUNIX系の用語って、プロセスを殺したり(kill)、 プロセスがゾンビ(zombie process)になったり、OSがあわてふためいたり(panic)、 茶目っ気のあるというか、コンピュータを擬人化したものが多いですね。

プログラムをしていると、そういう言葉を使うのは良く分かります。
プログラミングというのは、無意識にコンピュータやプログラムの「気持ち」を想像して、
「プログラムの立場に立って」ものを考えるからでしょうか。

開発の現場にいると、

この子があっちのサーバにリクエストを投げます。もしサーバがダンマリだったり
死んでたりしたら、仕方ないのでDBを見に行って別のサーバに投げなおします。

なんて発言は日常茶飯事、だれも気にせず使っていますが、

このプロセスがあっちのサーバにリクエストを送信します。もしサーバがレスポンスを
返さなかったり、サーバが起動していなかったりしたら、データベースを検索して、
別のサーバに送信しなおします。

というのが正しい日本語ですよね。

ご指摘などはこちらへ


URL B I U SIZE Black Maroon Green Olive Navy Purple Teal Gray Silver Red Lime Yellow Blue Fuchsia Aqua White

*1 ヒント:「.」はメタ文字です!
*2 ヒント:途中の空白が何文字か決まっていませんね
*3 ヒント:「へも」を単位とした繰り返しです
*4 ヒント:シングルラインモードは?
*5 ヒント:行の頭が#で始まっていますね
*6 ヒント:シングルラインモードは?
*7 ヒント:最後のリンクはどうしましょう