正規表現はコンピューターで検索、置換を行うための便利機能だ。
簡単な説明としては、本ブログの829回を読んでください。
イジハピ! : 【第829回】すぐわかる気がするPerl(19) エラーメッセージ ?+* follows nothing in regexp
簡単な説明としては、本ブログの829回を読んでください。
イジハピ! : 【第829回】すぐわかる気がするPerl(19) エラーメッセージ ?+* follows nothing in regexp
もっとも単純な正規表現は「固定文字列」である。
下のプログラムは「a」という文字を検索する。
$&はマッチ文字列(マッチした部分のこと。上のプログラムでは必ずa)、$_は読み込んだデータ行を表す。
次に簡単な正規表現は「.」で、任意の1文字を示す。
「a.t」を検索すると、a+任意の1文字+tという文字列を検索する。
aとtの間に1字だけ挟まっている言葉がantだけなので、そこが置換されている。
さて、?というメタ文字を正規表現の中に入れると、直前のパターンがゼロ回か1回出現する、という意味になる。
「a.?t」だと、aとtの間に1文字または0文字の任意の文字が入っているという意味になるので
antはaとtの間にnという1文字が入っていて、atom、annotationはaとtの間にゼロ文字の文字(空文字)が入っている。
このパターンにおける?のような、パターンの繰り返し回数を指定する正規表現を量指定子と言う。
*も量指定子で、直前のパターンをゼロ回以上繰り返すという意味になる。
「a.*t」だと、aとtの間にゼロ個以上の字が入るということなので
antはaとtの間にnが入っている。
auntはaとtの間にunが入っている。
atomはaとtの間に何も入らない。
annotationが微妙だ。
annotの時点でaとtの間にnnoが入っている。
でも、annotatまで読んで、aとtの間にnnotaが入るという解釈も出来るのだ。
プログラムの実行を見ると、a.*tという正規表現の場合、後者を取っているようだ。
このように、2通りの解釈が出来る場合は長い方を取る。
この現象を最大マッチという。
*はゼロ回以上の繰り返しの、最大マッチの量指定子ということになる。
+は1回以上の繰り返しの量指定子である。
a.+tはaとtの間に何か1文字以上入っているということになるから、
a.*tとくらべて、aとtの間に何も入っていないatomが除外された。
annotationの場合はやはり最大マッチが起こっている。
なお、a.+tは、a..*tと同じ意味になるが、a.+tの方が読みやすい。
{n}はきっかりn文字の、という意味である。
a.{3}tだと、aとtの間に3文字入っている、という意味になるので、
a.{3}tは、a...tと同じ意味になる。
この場合どっちが読みやすいとも言いがたい。
どっちも大して読みにくくない。
iとnの間に何らかの文字が18文字入っているという正規表現(internationalizationにマッチする)はi..................nとも書けるが、こうなるとi.{18}nの方が明らかに見やすいだろう。
{n,}はn回以上の繰り返しの量指定子だ。
a.{2,}tは、aとtの間に2文字以上入っているという意味になる。
{n,m}はn以上m以下の繰り返しという意味になる。
a.{1,4}tだとaとtの間に文字が1個以上4個以下入っているものを検索する。
これも、a..{0,3}tとか、a..?.?.?tとかいろんな書き方があるけど、素直に一番読みやすいa.{1,4}を使うのが良い。
ところで、全然話は逸れるのだが、しかもスッキリしない疑問なのだが、2つの任意の数を表すために、n、mとサラッと書いたが、これは昔から変だと思っていた。
数学で点を表すのにP、Q、Rと書く。
これは点PがPointの略であると思われる。
整数を書くのにi、jと書く。
これはiがintegerの略である。
同様に、nというのはnatural numberの略で自然数のことなのか、numberの略で番号ということなのか分からないが、これに続く数はoではなくmなのだ。
n始まりの時に限ってアルファベットを逆行するのである。
高校数学の時代から、n個のものからm個を取り出す組み合わせ(composition)はnCmとか、書くのがどうも気持ち悪かった。
閑話休題、量指定子には以下の種類がある。
では、複数の解釈が可能なとき、短い方を取ることはできるのだろうか。
できる。
量指定子に?を追加すればいいのである。
これは、たとえば、<b>で始まって</b>で終わる文字列とかいうときに、
a.+tの代わりにa.+?tと書いても、a.{2,}のa{2,}?と書いても、やはり最大マッチが最小マッチに変わる。
?(ゼロ回または1回)という量指定子にさらに?を付けて??とした場合はどうなるだろうか。
これは{0,1}と{0,1}?と同じと考えられる。
a.?nだと、aとnの間にゼロ文字または1文字の文字が入ったものを、最大マッチで検索する。
超・微妙だが、annotationにa.?tを作用させるとan(aとnの間にゼロ文字)と、ann(aとnの間に1文字)の2通りの解釈が成り立ったので、最大マッチでannを取った。
一方、a.??tを作用させると、同じ2通りの解釈のうち、最小マッチでanを取った。
それはいいのだが、{n}と{n}?の間に違いがあるのだろうか。
a{3}t(aとtの間にきっかり3文字、最大マッチ)というのと、a{3}?t(aとtの間にきっかり3文字、最小マッチ)というのと、どう違うのだろうか。
これは、違いはない。
{n}?は冗長な表現であり、{n}とまったく同じように動く。
おわかりですか。
そういうことらしいよ。
いろんな本にこの「違いがない」ということが書いていないので、あえて贅言を弄した。
下のプログラムは「a」という文字を検索する。
#! /usr/local/bin/perl実行してみる。
# regTest.pl -- 正規表現のテスト
use strict;
use warnings;
use utf8;
use 5.010;
binmode STDOUT, ":encoding(utf8)";
while() {
if (s/a/*$&*/) {
print "MATCHED in $_";
} else {
print "no match in $_";
}
}
__DATA__
This is a pen.
The pen is mine.
This is an egg.
The egg is yours.
This is my ant.
This is my aunt.
This is my atom.
This is my annotation.
$ regTest.plaという文字を検索して、*a*に置換し、置換が起こった場合はMATCHEDと出力している。
MATCHED in This is *a* pen.
no match in The pen is mine.
MATCHED in This is *a*n egg.
no match in The egg is yours.
MATCHED in This is my *a*nt.
MATCHED in This is my *a*unt.
MATCHED in This is my *a*tom.
MATCHED in This is my *a*nnotation.
$&はマッチ文字列(マッチした部分のこと。上のプログラムでは必ずa)、$_は読み込んだデータ行を表す。
次に簡単な正規表現は「.」で、任意の1文字を示す。
「a.t」を検索すると、a+任意の1文字+tという文字列を検索する。
#! /usr/local/bin/perlだと
# regTest.pl -- 正規表現のテスト
use strict;
use warnings;
use utf8;
use 5.010;
binmode STDOUT, ":encoding(utf8)";
while() {
if (s/a.t/*$&*/) {
print "MATCHED in $_";
} else {
print "no match in $_";
}
}
__DATA__
This is a pen.
The pen is mine.
This is an egg.
The egg is yours.
This is my ant.
This is my aunt.
This is my atom.
This is my annotation.
$ regTest.plとなる。
no match in This is a pen.
no match in The pen is mine.
no match in This is an egg.
no match in The egg is yours.
MATCHED in This is my *ant*.
no match in This is my aunt.
no match in This is my atom.
no match in This is my annotation.
aとtの間に1字だけ挟まっている言葉がantだけなので、そこが置換されている。
さて、?というメタ文字を正規表現の中に入れると、直前のパターンがゼロ回か1回出現する、という意味になる。
「a.?t」だと、aとtの間に1文字または0文字の任意の文字が入っているという意味になるので
$ regTest.plとなる。
no match in This is a pen.
no match in The pen is mine.
no match in This is an egg.
no match in The egg is yours.
MATCHED in This is my *ant*.
no match in This is my aunt.
MATCHED in This is my *at*om.
MATCHED in This is my annot*at*ion.
antはaとtの間にnという1文字が入っていて、atom、annotationはaとtの間にゼロ文字の文字(空文字)が入っている。
このパターンにおける?のような、パターンの繰り返し回数を指定する正規表現を量指定子と言う。
*も量指定子で、直前のパターンをゼロ回以上繰り返すという意味になる。
「a.*t」だと、aとtの間にゼロ個以上の字が入るということなので
$ regTest.plになる。
no match in This is a pen.
no match in The pen is mine.
no match in This is an egg.
no match in The egg is yours.
MATCHED in This is my *ant*.
MATCHED in This is my *aunt*.
MATCHED in This is my *at*om.
MATCHED in This is my *annotat*ion.
antはaとtの間にnが入っている。
auntはaとtの間にunが入っている。
atomはaとtの間に何も入らない。
annotationが微妙だ。
annotの時点でaとtの間にnnoが入っている。
でも、annotatまで読んで、aとtの間にnnotaが入るという解釈も出来るのだ。
プログラムの実行を見ると、a.*tという正規表現の場合、後者を取っているようだ。
このように、2通りの解釈が出来る場合は長い方を取る。
この現象を最大マッチという。
*はゼロ回以上の繰り返しの、最大マッチの量指定子ということになる。
+は1回以上の繰り返しの量指定子である。
a.+tはaとtの間に何か1文字以上入っているということになるから、
$ regTest.plとなる。
no match in This is a pen.
no match in The pen is mine.
no match in This is an egg.
no match in The egg is yours.
MATCHED in This is my *ant*.
MATCHED in This is my *aunt*.
no match in This is my atom.
MATCHED in This is my *annotat*ion.
a.*tとくらべて、aとtの間に何も入っていないatomが除外された。
annotationの場合はやはり最大マッチが起こっている。
なお、a.+tは、a..*tと同じ意味になるが、a.+tの方が読みやすい。
{n}はきっかりn文字の、という意味である。
a.{3}tだと、aとtの間に3文字入っている、という意味になるので、
$ regTest.plとなる。
no match in This is a pen.
no match in The pen is mine.
no match in This is an egg.
no match in The egg is yours.
no match in This is my ant.
no match in This is my aunt.
no match in This is my atom.
MATCHED in This is my *annot*ation.
a.{3}tは、a...tと同じ意味になる。
この場合どっちが読みやすいとも言いがたい。
どっちも大して読みにくくない。
iとnの間に何らかの文字が18文字入っているという正規表現(internationalizationにマッチする)はi..................nとも書けるが、こうなるとi.{18}nの方が明らかに見やすいだろう。
{n,}はn回以上の繰り返しの量指定子だ。
a.{2,}tは、aとtの間に2文字以上入っているという意味になる。
$ regTest.plこの場合も、annotationにおいて最大マッチが起こっている。
no match in This is a pen.
no match in The pen is mine.
no match in This is an egg.
no match in The egg is yours.
no match in This is my ant.
MATCHED in This is my *aunt*.
no match in This is my atom.
MATCHED in This is my *annotat*ion.
{n,m}はn以上m以下の繰り返しという意味になる。
a.{1,4}tだとaとtの間に文字が1個以上4個以下入っているものを検索する。
$ regTest.plannotationがannotにマッチしている。
no match in This is a pen.
no match in The pen is mine.
no match in This is an egg.
no match in The egg is yours.
MATCHED in This is my *ant*.
MATCHED in This is my *aunt*.
no match in This is my atom.
MATCHED in This is my *annot*ation.
これも、a..{0,3}tとか、a..?.?.?tとかいろんな書き方があるけど、素直に一番読みやすいa.{1,4}を使うのが良い。
ところで、全然話は逸れるのだが、しかもスッキリしない疑問なのだが、2つの任意の数を表すために、n、mとサラッと書いたが、これは昔から変だと思っていた。
数学で点を表すのにP、Q、Rと書く。
これは点PがPointの略であると思われる。
整数を書くのにi、jと書く。
これはiがintegerの略である。
同様に、nというのはnatural numberの略で自然数のことなのか、numberの略で番号ということなのか分からないが、これに続く数はoではなくmなのだ。
n始まりの時に限ってアルファベットを逆行するのである。
高校数学の時代から、n個のものからm個を取り出す組み合わせ(composition)はnCmとか、書くのがどうも気持ち悪かった。
閑話休題、量指定子には以下の種類がある。
? ゼロ回か1回の繰り返しすべて普通に書くと最大マッチであって、複数の解釈が可能な場合長い方を取る。
* ゼロ回以上の繰り返し
+ 1回以上の繰り返し
{n} n回の繰り返し
{n,} n回以上の繰り返し
{n,m} n回以上m回以下の繰り返し
では、複数の解釈が可能なとき、短い方を取ることはできるのだろうか。
できる。
量指定子に?を追加すればいいのである。
?? ゼロ回か1回の繰り返し(最小マッチ)さっきの「a.*t」を、「a.*?t」に変えてみる。
*? ゼロ回以上の繰り返し(最小マッチ)
+? 1回以上の繰り返し(最小マッチ)
{n}? n回の繰り返し(最小マッチ)
{n,}? n回以上の繰り返し(最小マッチ)
{n,m}? n回以上m回以下の繰り返し(最小マッチ)
$ regTest.pl見事にannotationで短い方のannotがマッチした。
no match in This is a pen.
no match in The pen is mine.
no match in This is an egg.
no match in The egg is yours.
MATCHED in This is my *ant*.
MATCHED in This is my *aunt*.
MATCHED in This is my *at*om.
MATCHED in This is my *annot*ation.
これは、たとえば、<b>で始まって</b>で終わる文字列とかいうときに、
<b>LOVE</b> and <b>KISS</b>というデータで、<b>.*</b>というパターンでは
<b>LOVE</b> and <b>KISS</b>全体にマッチしてしまうのが、
<b>.*?</b>というパターンに変えると、
<b>LOVE</b>と
<b>KISS</b>のそれぞれにマッチするので便利だ。
a.+tの代わりにa.+?tと書いても、a.{2,}のa{2,}?と書いても、やはり最大マッチが最小マッチに変わる。
?(ゼロ回または1回)という量指定子にさらに?を付けて??とした場合はどうなるだろうか。
これは{0,1}と{0,1}?と同じと考えられる。
a.?nだと、aとnの間にゼロ文字または1文字の文字が入ったものを、最大マッチで検索する。
$ regTest.plこれに対して、やはりa.??nだと、aとnの間にゼロ文字または1文字の文字が入ったものを、最小マッチで検索する。
no match in This is a pen.
no match in The pen is mine.
MATCHED in This is *an* egg.
no match in The egg is yours.
MATCHED in This is my *an*t.
MATCHED in This is my *aun*t.
no match in This is my atom.
MATCHED in This is my *ann*otation.
$ regTest.plどこが変わったか分かりますか。
no match in This is a pen.
no match in The pen is mine.
MATCHED in This is *an* egg.
no match in The egg is yours.
MATCHED in This is my *an*t.
MATCHED in This is my *aun*t.
no match in This is my atom.
MATCHED in This is my *an*notation.
超・微妙だが、annotationにa.?tを作用させるとan(aとnの間にゼロ文字)と、ann(aとnの間に1文字)の2通りの解釈が成り立ったので、最大マッチでannを取った。
一方、a.??tを作用させると、同じ2通りの解釈のうち、最小マッチでanを取った。
それはいいのだが、{n}と{n}?の間に違いがあるのだろうか。
a{3}t(aとtの間にきっかり3文字、最大マッチ)というのと、a{3}?t(aとtの間にきっかり3文字、最小マッチ)というのと、どう違うのだろうか。
これは、違いはない。
{n}?は冗長な表現であり、{n}とまったく同じように動く。
おわかりですか。
そういうことらしいよ。
いろんな本にこの「違いがない」ということが書いていないので、あえて贅言を弄した。