|
|
|||||||||||||||||||||||||||||
|
Perl正規表現の使い方 任意の文字と繰り返し(量指定子) |
H.Kamifuji . |
|
文字列の中のある箇所だけはどんな文字であっても構わない場合や、一部の文字が何個連続していても構わない場合などについても1つの正規表現で表すことが可能です。ここでは任意の文字を表現する方法や特定の文字に対する繰り返し指定の方法を確認していきます。 当ページでは、Linux CentOS7 の Gnome で動作テストしています。 |
|
|
|
メタ文字の1つであるドット(.)をパターンの中に記述すると改行(\n)を除く任意の一文字にマッチします。 例えば次のように記述します。 /ab.cd/上記の場合、ドット(.)は任意の一文字にマッチしますので「abfcd」や「ab0cd」などドット(.)が記述された位置にどんな文字が書かれている場合もマッチすることになります。 注意する点としては任意の一文字ですので必ず一文字必要です。よって「ab」と「cd」の間に文字が無いような「abcd」や2つ以上の文字が含まれるような「abloocd」はマッチしません。 マッチするもの: abhcd ab4cd ab#cdマッチしないもの: abcd abppcdメタ文字「.」は何個でも使いことができます。 /ab..cd/この場合は「ab」と「cd」の間に任意の二文字がある文字列にマッチします。(例:abomcdd)。 /a.b.c.d/この場合は「a」「b」「c」「d」の各文字の間に1つずつ任意の文字がある文字列にマッチします。(例:a1b2c3d)。 改行文字の扱いメタ文字「.」は任意の一文字にマッチします。これはアルファベットや数字だけではなくタブである「\t」などでもマッチしますが、改行である「\n」だけはマッチしません。そこでパターンの中で単独で「^」を記述する場合を考えてみます。
my $str = "a\n";
if ($str =~ /a./){
# ...
}
例えば上記のような場合にはマッチしませんので注意して下さい。改行もマッチするようにするには「メタ文字(.)が改行にマッチ(「/s」修飾子)」を参照して下さい。では簡単なプログラムで確認して見ます。 test1-1.pl サンプルプログラム下記のサンプルを実行してみよう。
# 任意の一文字(.)
use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
print "「ab.cd」にマッチするかどうか\n\n";
&check("ab6cd");
&check("abycd");
&check("ab\tcd");
&check("ab\ncd");
&check("abcd");
&check("abpocd");
sub check{
my ($str) = @_;
if ($str =~ /ab.cd/){
print "○:$str\n";
}else{
print "×:$str\n";
}
}
上記を「test1-1.pl」の名前で保存してから次のように実行して下さい。![]() Linux 環境での実行結果は、下記です。シフトJIS で出力されるので nkf -w で UTF-8 に変換しています。 [xxxxxxxx@dddddddddd Repeat]$ perl test1-1_u.pl | nkf -w 「ab.cd」にマッチするかどうか ○:ab6cd ○:abycd ○:ab cd ×:ab cd ×:abcd ×:abpocd [xxxxxxxx@dddddddddd Repeat]$ |
|
メタ文字の1つであるアスタリスク(*)をパターンの中に記述すると、アスタリスクの前にある文字が0回以上繰り返したものにマッチします。0回と言うのは対象の直前の文字が存在しない場合です。 例えば次のように記述します。
/Go*gle/
上記の場合、アスタリスク(*)は直前の文字(今回は「o」)に0回以上繰り返したものにマッチします。0回以上というのは「o」が無い場合と「o」や「oooo」など「o」が1回以上繰り返されている文字マッチするということになります。(直前の文字が無い場合は、空文字にマッチしていることになります)。 マッチするもの: Ggle Gogle Google Gooogle Goooogle Gooooogle0回も含まれる点に注意して下さい。 では簡単なプログラムで確認して見ます。 test2-1.pl サンプルプログラム下記のサンプルを実行してみよう。
# 直前の文字を0回以上繰り返し(*)
use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
print "「Go*gle」にマッチするかどうか\n\n";
&check("Ggle");
&check("Gogle");
&check("Google");
&check("Goooooogle");
&check("Gmgle");
&check("Gomogle");
sub check{
my ($str) = @_;
if ($str =~ /Go*gle/){
print "○:$str\n";
}else{
print "×:$str\n";
}
}
上記を「test2-1.pl」の名前で保存してから次のように実行して下さい。![]() Linux 環境での実行結果は、下記です。シフトJIS で出力されるので nkf -w で UTF-8 に変換しています。 [xxxxxxxx@dddddddddd Repeat]$ perl test2-1_u.pl | nkf -w 「Go*gle」にマッチするかどうか ○:Ggle ○:Gogle ○:Google ○:Goooooogle ×:Gmgle ×:Gomogle [xxxxxxxx@dddddddddd Repeat]$ |
|
メタ文字の1つであるプラス(+)をパターンの中に記述すると、プラスの前にある文字を1回以上繰り返したものにマッチします。 例えば次のように記述します。
/Go+gle/
上記の場合、プラス(+)は直前の文字(今回は「o」)に1回以上繰り返したものにマッチします。1回以上というのは「o」が必ず1回は必要になりますので「o」や「oooo」などにマッチするということになります。 マッチするもの: Gogle Google Gooogle Goooogle Gooooogleメタ文字のアスタリスク(*)が0回以上だったのに対してプラス(+)は必ず1回は必要な場合に使用して下さい。 では簡単なプログラムで確認して見ます。 test3-1.pl サンプルプログラム下記のサンプルを実行してみよう。
# 直前の文字を1回以上繰り返し(+)
use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
print "「Go+gle」にマッチするかどうか\n\n";
&check("Ggle");
&check("Gogle");
&check("Google");
&check("Gooooogle");
&check("Gmgle");
&check("Gomgle");
sub check{
my ($str) = @_;
if ($str =~ /Go+gle/){
print "○:$str\n";
}else{
print "×:$str\n";
}
}
上記を「test3-1.pl」の名前で保存してから次のように実行して下さい。![]() Linux 環境での実行結果は、下記です。シフトJIS で出力されるので nkf -w で UTF-8 に変換しています。 [xxxxxxxx@dddddddddd Repeat]$ perl test3-1_u.pl | nkf -w 「Go+gle」にマッチするかどうか ×:Ggle ○:Gogle ○:Google ○:Gooooogle ×:Gmgle ×:Gomgle [xxxxxxxx@dddddddddd Repeat]$ |
|
メタ文字の1つであるクエスチョン(?)をパターンの中に記述すると、クエスチョンの前にある文字が0回か1回現れる場合にマッチします。0回と言うのは対象の直前の文字が存在しない場合です。 例えば次のように記述します。
/Go?gle/
上記の場合、クエスチョン(?)は直前の文字(今回は「o」)が省略されるか1回だけ現れた場合にマッチします。その為、今回の場合でマッチするのは「o」が無い場合と「o」が1回だけ現れた場合です。(直前の文字が無い場合は、空文字にマッチしていることになります)。 マッチするもの: Ggle Gogleメタ文字のプラス(+)やアスタリスク(*)よりも、より限定的なものとなります。 では簡単なプログラムで確認して見ます。 test4-1.pl サンプルプログラム下記のサンプルを実行してみよう。
# 直前の文字が0回か1回(?)
use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
print "「Go?gle」にマッチするかどうか\n\n";
&check("Ggle");
&check("Gogle");
&check("Google");
&check("Gooooogle");
&check("Gmgle");
&check("Gomgle");
sub check{
my ($str) = @_;
if ($str =~ /Go?gle/){
print "○:$str\n";
}else{
print "×:$str\n";
}
}
上記を「test4-1.pl」の名前で保存してから次のように実行して下さい。![]() Linux 環境での実行結果は、下記です。シフトJIS で出力されるので nkf -w で UTF-8 に変換しています。 [xxxxxxxx@dddddddddd Repeat]$ perl test4-1_u.pl | nkf -w 「Go?gle」にマッチするかどうか ○:Ggle ○:Gogle ×:Google ×:Gooooogle ×:Gmgle ×:Gomgle [xxxxxxxx@dddddddddd Repeat]$ |
|
今まで見てきた「*」「+」「?」については直前の文字を0個、1個、又は1個以上繰り返し現れた場合にマッチしていましたが、指定した範囲の間の数だけ繰り返し表れる場合にマッチする正規表現を記述できます。 記述方法は次のようになります。
{min,max}
指定する範囲は「min」及び「max」で指定します。例えば直前の文字が2回から4回の範囲で繰り返し現れる場合にマッチする場合は次のように記述します。
/Go{2,4}gle/
上記の場合、直前の文字(今回は「o」)が指定した範囲の2回から4回の間繰り返し現れた場合にマッチします。その為、今回の場合でマッチするのは「oo」「ooo」「oooo」の場合です。 マッチするもの: Google Gooogle Goooogle 2番目の引数を省略する2番目の引数を省略すると、直前の文字が現れることができる上限が無くなります。
{min,}
カンマ(,)は省略しないで下さい。省略した場合は別の意味となります。指定する範囲は「min」だけを指定します。例えば直前の文字が2回以上繰り返し現れる場合にマッチする場合は次のように記述します。
/Go{2,}gle/
上記の場合、直前の文字(今回は「o」)が指定した範囲の2回以上繰り返し現れた場合にマッチします。その為、今回の場合でマッチするのは「oo」「ooo」「oooooooo」などです。 マッチするもの: Google Gooogle Goooogle Gooooogle Goooooogle Gooooooogle 回数を指定する1番目の引数だけを指定する(2番目の引数とカンマを省略する)と指定した回数だけ直前の文字が現れる場合にマッチします。
{num}
繰り返し現れることができる回数を1つだけ指定します。例えば直前の文字が2回現れる場合にだけマッチする場合は次のように記述します。
/Go{2}gle/
上記の場合、直前の文字(今回は「o」)が2回現れた場合にマッチします。その為、今回の場合でマッチするのは「oo」だけです。 マッチするもの: メタ文字「*」「+」「?」との関係今回の範囲指定を使えばアスタリスク(*)、プラス(+)、クエスチョン(?)のメタ文字と同じことをすることが出来ます。
* {0,} 直前の文字を0回以上繰り返し
+ {1,} 直前の文字を1回以上繰り返し
? {0,1} 直前の文字が0回か1回
どちらの表記を使っても構いませんが、条件に合うのであれば「*」「+」「?」のメタ文字を使用した方がコンパクトに記述することが可能です。では簡単なプログラムで確認して見ます。 test5-1.pl サンプルプログラム下記のサンプルを実行してみよう。
# 直前の文字を指定した範囲の回数繰り返し({min,max})
use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
print "「Go{1,2}gle」にマッチするかどうか\n\n";
&check("Ggle");
&check("Gogle");
&check("Google");
&check("Gooogle");
&check("Gmgle");
&check("Gomgle");
sub check{
my ($str) = @_;
if ($str =~ /Go{1,2}gle/){
print "○:$str\n";
}else{
print "×:$str\n";
}
}
上記を「test5-1.pl」の名前で保存してから次のように実行して下さい。![]() Linux 環境での実行結果は、下記です。シフトJIS で出力されるので nkf -w で UTF-8 に変換しています。
[xxxxxxxx@dddddddddd Repeat]$ perl test5-1_u.pl | nkf -w
「Go{1,2}gle」にマッチするかどうか
×:Ggle
○:Gogle
○:Google
×:Gooogle
×:Gmgle
×:Gomgle
[xxxxxxxx@dddddddddd Repeat]$
|
|
メタ文字の「*」「+」「?」及び範囲を指定する{min,max}を使用する場合、対象は直前の一文字でした。ここでは一文字ではなく複数の文字を1つのグループとして扱い、複数の文字を繰り返しの対象にする方法を確認します。 複数の文字を対象にするには、複数の文字を()で囲みグループにします。記述方法は次のようになります。 (複数の文字)*例えば「good!」と言う4つの文字が1回以上繰り返されて現れた場合にマッチする正規表現は次の通りです。 /(good!)+/上記の場合、「(」から「)」で囲まれた間に書かれた文字が1つのグループとなります。そしてメタ文字の「+」は直前にある文字が1回以上繰り返された場合にマッチしますが、今回は直前の文字がグループなのでグループの中の複数の文字が1回以上繰り返された場合にマッチします。 マッチするもの: good! good!good! good!good!good!good!good!このように()で囲まれた複数の文字を1つの単語のように扱い、単語が繰り返しの対象となります。 今回はグループにすることで繰り返しの対象を一つの文字以外にも適用するようにしましたが、繰り返しを表すメタ文字はその直前にあるものが対象となり一つの文字だけが対象とならない場合もあります。具体的には他のページで順次解説していきます。 では簡単なプログラムで確認して見ます。 test6-1.pl サンプルプログラム下記のサンプルを実行してみよう。
# グループ化して複数の文字を対象にする
use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
print "「G(oog)+le」にマッチするかどうか\n\n";
&check("Gle");
&check("Goole");
&check("Google");
&check("Googoogle");
&check("Googoogoogle");
&check("Googole");
&check("Googgle");
&check("Googogole");
sub check{
my ($str) = @_;
if ($str =~ /G(oog)+le/){
print "○:$str\n";
}else{
print "×:$str\n";
}
}
上記を「test6-1.pl」の名前で保存してから次のように実行して下さい。![]() Linux 環境での実行結果は、下記です。シフトJIS で出力されるので nkf -w で UTF-8 に変換しています。 [xxxxxxxx@dddddddddd Repeat]$ perl test6-1_u.pl | nkf -w 「G(oog)+le」にマッチするかどうか ×:Gle ×:Goole ○:Google ○:Googoogle ○:Googoogoogle ×:Googole ×:Googgle ×:Googogole [xxxxxxxx@dddddddddd Repeat]$ |
|
任意の一文字にマッチするメタ文字(.)とメタ文字(*)やメタ文字(+)を組み合わせることで、任意の文字が繰り返し現れた場合にマッチする正規表現を作成することが出来ます。 例として「a」と「b」の間に任意の文字が繰り返し現れるパターンは次のようになります。
/a.+b/
上記の場合、メタ文字(+)の直前の文字がメタ文字(.)となっています。「+」は直前の文字を1回以上繰り返す場合にマッチし、「.」は任意の一文字にマッチします。結果として「.+」は任意の文字が1回以上繰り返す場合にマッチすることになります。よって「a」と「b」の間にどんな文字が何文字記述されていてもマッチすることになります。 マッチするもの: aPb abowb a1098opebまた詳しくは次のページで解説しますがデフォルトでは最大限にマッチする範囲が多くなる位置でマッチします。 a0000b1111b2222b対象が上記のような文字列だった場合にパターン「/a.+b/」は「a0000b」にも「a0000b1111b」にも「a0000b1111b2222b」にもマッチします。このような場合はマッチする範囲が最大にある「a0000b1111b2222b」にマッチします。 改行も含めて任意の文字を繰り返す任意の一文字を表すメタ文字(.)は改行にはマッチしません。そこで改行も含めて任意の文字を繰り返す場合には別の記述方法を使います。例として「a」と「b」の間に改行も含めた任意の文字が繰り返し現れるパターンは次のようになります。
/a[\d\D].+b/
この場合、文字クラスを表すブラケット[]の中に数字を表す「\d」と数字以外を表す「\D」を記述しています。文字クラスは[]に列挙された文字のいずれかにマッチしますので、数字か数字以外のいずれかにマッチすることになりますので結果として全ての文字にマッチすることになります。(文字クラスについては「いずれかの文字に一致(文字クラス)」を参照して下さい)。 同じように「/[\w\W]+/」や「/[\s\S]+/」でも同じです。また「/s修飾子」を使用しても可能ですが、こちらはまた修飾子の箇所で解説します。 では簡単なプログラムで確認して見ます。 test7-1.pl サンプルプログラム下記のサンプルを実行してみよう。
# 任意の文字を繰り返し
use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
print "「P.+P」にマッチするかどうか\n";
print "(マッチする場合は括弧の中にマッチした部分を表示)\n\n";
&check1("aPooPa");
&check1("aPoPoPa");
&check1("aPoo\nPmmmPa");
print "\n「P[\\d\\D]+P」にマッチするかどうか\n";
&check2("aPoo\nPmmmPa");
sub check1{
my ($str) = @_;
if ($str =~ /P.+P/){
print "○:$str ($&)\n";
}else{
print "×:$str\n";
}
}
sub check2{
my ($str) = @_;
if ($str =~ /P[\d\D]+P/){
print "○:$str ($&)\n";
}else{
print "×:$str\n";
}
}
上記を「test7-1.pl」の名前で保存してから次のように実行して下さい。![]() 今回の場合、マッチした場合にはどの部分にマッチしたのかを合わせて表示するようにしています。「aPoo\nPmmmPa」に対し、パターン「/P.+P/」は「Poo\nP」にはマッチしないため「PmmmP」にマッチします。それに対して「P[\d\D]+P」は改行も含めてマッチするため「Poo\nPmmmP」にマッチします。 Linux 環境での実行結果は、下記です。シフトJIS で出力されるので nkf -w で UTF-8 に変換しています。 [xxxxxxxx@kddddddddd Repeat]$ perl test7-1_u.pl | nkf -w 「P.+P」にマッチするかどうか (マッチする場合は括弧の中にマッチした部分を表示) ○:aPooPa (PooP) ○:aPoPoPa (PoPoP) ○:aPoo PmmmPa (PmmmP) 「P[\d\D]+P」にマッチするかどうか ○:aPoo PmmmPa (Poo PmmmP) [xxxxxxxx@kddddddddd Repeat]$ |
|
前のページで簡単に確認しましたが、デフォルトでは最大限にマッチする範囲が多くなる位置でマッチします。これはメタ文字の「+」「*」「?」「{min,max}」のどれを使った場合でも同じです。 例として前のページで使用した任意の文字を表すメタ文字「.」に対して1回以上繰り返しすメタ文字「+」を使った場合で考えてみます。
/a.+b/
上記は「a」で始まり任意の文字が連続して続き「b」で終わる文字列にマッチします。このパターンを文字列「00a11b22b33b44」に対して適用すると次の位置でマッチする可能性があります。
00a11b22b33b44
00a11b22b33b44 00a11b22b33b44 この時、デフォルトではマッチする範囲が最大になるようにマッチするため、実際にマッチするのは次の位置になります。
00a11b22b33b44
このように最大の範囲でマッチすることを「欲張りなマッチ」と呼ばれています。 場合によってはマッチする範囲が最小になるようにマッチさせたい場合もあります。この時は各メタ文字の後に「?」を付けて使用します。
+?
*?
??
{min,max}?
{min,}?
{num}?
例として先ほどと同じように任意の文字を表すメタ文字「.」に対して1回以上繰り返しすメタ文字「+?」を使った場合で考えてみます。今回は最小量指定子付きとなっています。
/a.+?b/
上記は「a」で始まり任意の文字が連続して続き「b」で終わる文字列にマッチします。このパターンを文字列「00a11b22b33b44」に対して適用すると次の位置でマッチする可能性があります。
00a11b22b33b44
00a11b22b33b44 00a11b22b33b44 今回は最小量指定子が付いていますのでマッチする範囲が最小になるようにマッチするため、実際にマッチするのは次の位置になります。
00a11b22b33b44
このように最小の範囲でマッチすることを「控え目なマッチ(又は欲張りでないマッチ)」と呼ばれています。 では簡単なプログラムで確認して見ます。 test8-1.pl サンプルプログラム下記のサンプルを実行してみよう。
# 欲張りなマッチと控え目なマッチ(最小量指定子)
use strict;
use warnings;
use utf8;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
print "「P.+P」にマッチするかどうか\n";
&check1("aP12Pa");
&check1("aP12P34Pa");
&check1("aP12P34P56Pa");
print "\n「P.+?P」にマッチするかどうか\n";
&check2("aP12Pa");
&check2("aP12P34Pa");
&check2("aP12P34P56Pa");
sub check1{
my ($str) = @_;
if ($str =~ /P.+P/){
print "○:$str ($&)\n";
}else{
print "×:$str\n";
}
}
sub check2{
my ($str) = @_;
if ($str =~ /P.+?P/){
print "○:$str ($&)\n";
}else{
print "×:$str\n";
}
}
上記を「test8-1.pl」の名前で保存してから次のように実行して下さい。![]() Linux 環境での実行結果は、下記です。シフトJIS で出力されるので nkf -w で UTF-8 に変換しています。 [xxxxxxxx@dddddddddd Repeat]$ perl test8-1_u.pl | nkf -w 「P.+P」にマッチするかどうか ○:aP12Pa (P12P) ○:aP12P34Pa (P12P34P) ○:aP12P34P56Pa (P12P34P56P) 「P.+?P」にマッチするかどうか ○:aP12Pa (P12P) ○:aP12P34Pa (P12P) ○:aP12P34P56Pa (P12P) [xxxxxxxx@dddddddddd Repeat]$ |
|
|