正規表現の最短マッチの使い方

最短マッチの意味自体はそんなに難しくない。まず最初に通常(最短マッチでない)の場合の説明。

<title>cloned.log</title>

という箇所に対して

<.*>

というパターンを書いてしまうと


<title>cloned.log</title>

の全てがパターンにマッチしているとみなされる。途中で>が一度出現しているけれど、最後に出てきた>までが「一つのパターン」としてみなされる。
何が困るかというと、例えば上記の場合だとタグだけを引っ掛けたいときに困る。要は、


<title>cloned.log</title>

としたいとき。ここで登場するのが最短マッチ。ここの例で言えば、<から始まって最初に>が出てくるまでを「一つのパターン」としてみなしたい訳だ。答えから書くと、

<.*?>

となる。?が最短マッチのメタ文字。
ここまでだとそんなに難しくない印象なので、応用して、<a name=”hoge“>hoge</a>みたいなパターンを探すときの場合を考えてみる。最短マッチを意識しないなら、

<a\s+name=".+">.+</a>

みたいな感じ(話を簡単にするためにタグ内に空白があった場合とかは考慮してないパターンにしている)。一応説明すると、\s+は空白が一つ以上で.+は何かしらの文字を一つ以上という意味になる。
但し、最初に書いたとおり、これだと最長マッチになるので、


<a name="foo">foo</a>www<a name="hoge">hoge</a>

が「一つのパターン」としてみなされてしまう。中央のwwwは一致してもらっては困るので、再び最短マッチに登場してもらう必要がある。
個人的にはここが挫折のポイントだった。自分の発想では、

(<a\s+name=".+">.+</a>)?

と書きたかった。「こういうパターンを最短マッチでお願い!」というイメージを持っていたためだ。しかし、これは間違い。
よく考えればわかるのだけど、最短とか最長とかというのは長さが決まっていないから出てくる発想。では今回のパターンで長さが決まっていないのはどこか。
答えはs+と.+の部分になる。+がついているので、一つ以上は何個でも良いため長さが定まらない。そこで「*や+という繰り返しをどこまでやるのか?」という問いに「繰り返しは最小でお願いします」と注文するのが最短マッチ(メタ文字?を付ける)ということになる。
ということで、先程の例を


<a name="foo">foo</a>www<a name="hoge">hoge</a>

としたい場合には、

<a\s+?name=".+?">.+?</a>

というパターンを書けば良い。これで、次の文字(文字というかパターンだけど)が出現するまでの繰り返しを最短で終了するという意味になる。
もっと細かく書くと、「<a」の次に空白を一つ以上繰り返すが、最初に「n」があるところまでをパターンマッチとみなす。次に「name=”」まではそのままの文字があるかを確かめて、「.+?」とあるので次の文字である「”」が最初に出現した箇所でパターンマッチとみなす。
といった流れになる(多分正規表現のプログラムはもっと効率の良い探しかたをしている筈なので、あくまで人が理解するという意味で)。

正規表現を最初見たときはモールス信号かと思うくらい意味がわからなかったけれど、幸いメタ文字の数がそこまで多くないので、案外簡単に覚えられた。ただ、この最短マッチについては理解するのに苦労した思い出があったので何となく書いてみた。

4件のコメント

  1. 最短マッチで検索をかけてたどり着きました。
    解説ありがとうございます。印刷して読んでいます。

  2. おかげさまで同様の問題が解決できました。
    ありがとうございます。

  3. 同様のケースで行き詰まっていたので、助かりました!
    ありがとうございます。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です