正規表現の最短マッチと最長マッチについて

正規表現の最短マッチと最長マッチについて

Posted at November 28,2013 1:55 AM
Tag:[Perl]

正規表現の最短マッチと最長マッチについて紹介します。

最短マッチ

1.問題点

次のようなHTML文書があると仮定します。

<div>aaa</div>
<div>bbb</div>
<div>ccc</div>

この文書からHTMLタグだけを取り除くために、Perlで次のように書いてみます。

#!/usr/bin/perl
 
use strict;
 
my $foo = <<EOF;
<div>aaa</div>
<div>bbb</div>
<div>ccc</div>
EOF
 
$foo =~ s/<.+>//g;
print $foo;

このスクリプトを実行すると、何も出力されません(厳密には改行文字が出力)。

2.最長マッチについて

1項で何も表示されない原因は、s///演算子による正規表現で「最長マッチ」を適用しているためです(赤色部分 )。

$foo =~ s/<.+>//g;

サンプルの「.+(1回以上の繰り返し)」、あるいは「.*(0回以上の繰り返し)」は最長マッチとなり、Perlであればデフォルトのパターンマッチになります。

つまり上記のように記述すると、各行頭の「<」と、マッチが可能な最後尾の文字、つまり行末の「>」にマッチします(下の赤色部分)。

<div>aaa</div>
<div>bbb</div>
<div>ccc</div>

3.最短マッチについて

サンプルで「aaa」などのテキスト部分のみを残すには、HTMLタグの「<」のあとで最初に出現する「>」、つまり最短マッチさせる必要があります。

最短マッチさせるには、次のように「?」を加えます。

$foo =~ s/<.+?>//g;

「?」は量指定子を示すものではなく、量指定子の直後に指定することで最短マッチを示す役割を果たします。

上記のように記述することで、以下の赤色部分がマッチするようになります。

<div>aaa</div>
<div>bbb</div>
<div>ccc</div>

修正したスクリプトは以下のとおりです。

#!/usr/bin/perl
 
use strict;
 
my $foo = <<EOF;
<div>aaa</div>
<div>bbb</div>
<div>ccc</div>
EOF
 
$foo =~ s/<.+?>//g;
print $foo;

これで次のような出力を得ることができます。

aaa
bbb
ccc

2014.2.18
説明に誤りがあったので修正しました。

関連記事
トラックバックURL


コメント

「最長マッチについて」の説明が誤っています.

s/<.+>//g

の場合, '.'(ドット)は改行記号にはマッチしません.
そのため, 一番最後の '>'でなく, 各行の末尾の '>'に
マッチしています. その証拠にそのコードを実行したとき,
3つの改行が表示されるはずです.

説明のとおり最後の '&;gt'にマッチさせようとすると,
's'フラグをつける必要があります.

s/<.+>//sg

's'フラグは '.'を改行文字を含む任意の文字にマッチさせる
ためのフラグです. これで同じスクリプトを実行した場合,
改行が 1つしか表示されないことになります.

[1] Posted by syohex logo : November 29, 2013 10:41 AM

>syohexさん
ご返事遅くなりすいません。

ご指摘ありがとうございます。
おっしゃる通りドットは改行を含まない認識でしたが、推敲時に勘違いしてしまったようです。
記事は修正致しました。

[2] Posted by yujiro logo : February 18, 2014 1:24 PM
コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)