(delimiter) のように ( ) で囲まれた英語句は、その直前の訳語が原文でどう書かれているかを示しています。プログラミングの常識として把握しておくべき語句だったり、ログメッセージなどで実際に出くわす機会があるため英語表記を知っておいたほうがいい場合などに用いています。
最も単純な正規表現とは、単語。もっと普遍的に言えば、ひと集まりの文字 (a string of characters) だ。或る単語ひとつから成る正規表現は、その単語を含むあらゆる文字列にマッチする。
"Hello World" =~ /World/; # マッチする
この記述では World が正規表現で、 /World/ を囲んでいる // が perl に、一致するひとかたまりの文字列を探せと命令している。演算子 =~ はその文字列を正規表現マッチに結びつけ、正規表現がマッチすれば真 (a true value) を発生させ、マッチしなければ偽 (false) を発生させる。上記の例で言うと、 World は "Hello World" の中のふたつめの単語にマッチするので、式 (the expression) は真となる。この考え方を基本にして、幾つものバリエーションができている。
こういった式は条件分岐で便利だ:
print "It matches\n" if "Hello World" =~ /World/;
マッチは != 演算子で意味を反転できる:
print "It doesn't match\n" if "Hello World" !~ /World/;
正規表現の中で文字列そのものの代わりに変数を使うことも可能だ:
$greeting = "World"; print "It matches\n" if "Hello World" =~ /$greeting/;
$_
に対してマッチングを行う場合には $_ =~ という部分は省略できる:
$_ = "Hello World"; print "It matches\n" if /World/;
つまるところ、 // というデフォルトの区切り文字 (delimiter) は、'm' を先頭に付けることでどんな区切り文字にでも変更できる:
"Hello World" =~ m!World!; # マッチする。'!' が区切り文字 "Hello World" =~ m{World}; # マッチする。'{}' は対になっていることに注意 "/usr/bin/perl" =~ m"/perl"; # '/usr/bin' の後ろにマッチする。 # '/' は通常の文字として扱われている
正規表現部がその文字列の或る一箇所とぴったり一致しないと、式は真とはならない:
"Hello World" =~ /world/; # マッチしない。大文字小文字は区別される "Hello World" =~ /o W/; # マッチする。' ' もひとつの文字だ "Hello World" =~ /World /; # マッチしない。最後に ' ' がないから
perl は常に、文字列の中でマッチの成立する最も早い出現ポイントに一致しようとする
"Hello World" =~ /o/; # 'Hello' の 'o' にマッチ "That hat is red" =~ /hat/; # 'That' の 'hat' にマッチ
マッチングでは「生」では使えない文字もある。メタキャラクタ (metacharacters) と呼ばれる文字は、正規表現用の印として確保されて (reserved) いる。これらがメタキャラクタだ:
{}[]()^$.|*+?\
メタキャラクタをマッチさせるにはその手前にバックスラッシュを置けばよい:
"2+2=4" =~ /2+2/; # マッチしない。+ はメタキャラクタだ "2+2=4" =~ /2\+2/; # マッチする。\+ は通常の + として扱われる 'C:\WIN32' =~ /C:\\WIN/; # マッチする "/usr/bin/perl" =~ /\/usr\/bin\/perl/; # マッチする
最後の正規表現ではスラッシュ '/' もバックスラッシュ付きになっている。スラッシュは正規表現の区切り文字として使われているからだ。
表示用でない (non-printable) ASCII文字はエスケープシーケンス (escape sequence) で表現できる。よく使うものに、タブを表す \t、改行 (newline) を表す \n、キャリッジリターン(復帰改行文字)(carrage return) を表す \r がある。任意のバイト値は、 \033 のような 8進のエスケープシーケンス、または、 \x1B のような16進のエスケープシーケンスで表すことができる。
"1000\t2000" =~ m(0\t2) # マッチする "cat" =~ /\143\x61\x74/ # マッチする。誰も cat をこんな風には書かないが
正規表現はたいてい、ダブルクォートされた文字列として扱われる。よって、変数による置き換えがきく:
$foo = 'house'; 'cathouse' =~ /cat$foo/; # マッチする 'housecat' =~ /${foo}cat/; # マッチする
上に挙げた正規表現はいずれも、その正規表現が文字列のどこであれ一致すれば、即ちマッチしたことになる。一致する位置を指定したい場合には、アンカー(anchor)メタキャラクタ ^ と $ を使えばできる。 ^ というアンカーは、その文字列の先頭へのマッチを意味する。 $ というアンカーはその文字列の終端、あるいは、終端にある改行文字の手前にマッチすることを意味する。例を幾つか示そう:
"housekeeper" =~ /keeper/; # マッチする "housekeeper" =~ /^keeper/; # マッチしない "housekeeper" =~ /keeper$/; # マッチする "housekeeper\n" =~ /keeper$/; # マッチする "housekeeper" =~ /^housekeeper$/; # マッチする
文字クラス (character class) を使うと、単一の文字ではなく、複数の候補文字を指定することができ、これは正規表現の中の好きな場所で使うことができる。文字クラスは、中に複数の候補を並べた [...] で表す。幾つか例を示そう:
/cat/; # 'cat' にマッチ /[bcr]at/; # 'bat' か 'cat' か 'rat' にマッチ "abc" =~ /[cab]/; # 'a' がマッチする
最後の記述で、'c' がクラスの最初の文字になっているが、それにもかかわらず、正規表現を満たす一番最初のポイントは 'a' となる。
/[yY][eE][sS]/; # 大文字小文字を区別しない形で 'yes' にマッチする。 # 'yes' や 'Yes' や 'YES' などだ /yes/i; # これも大文字小文字の区別なしで 'yes' にマッチ
最後のものは i 修飾子 (modifier) の使用例を示している。 i 修飾子はマッチを大文字小文字の区別無視 (case-insensitive) にさせる。
文字クラスにも通常文字と特別な文字がある。ただし、文字クラス内での通常文字と特殊文字の区別は、文字クラス外の時とは異なる。文字クラスでの特殊文字は -]\^$ で、これらはエスケープ記号を使わないとマッチさせることができない。
/[\]c]def/; # ']def' か 'cdef' にマッチ $x = 'bcr'; /[$x]at/; # 'bat' か 'cat' か 'rat' にマッチ /[\$x]at/; # '$at' か 'xat' にマッチ /[\\$x]at/; # '\at' か 'bat' か 'cat' か 'rat' にマッチ
文字クラスの中では、特殊文字 '-' は範囲を示す記号として機能する。不格好な [0123456789] と [abc...xyz] が、小綺麗に [0-9] と [a-z] となるわけだ。
/item[0-9]/; # 'item0' から延々 'item9' までのいずれかにマッチ /[0-9a-fA-F]/; # 英数文字ひとつにマッチ
'-' が文字クラスの最初または最後に来ている場合には、 '-' は通常の文字として扱われる。
特殊文字 ^ が文字クラスの先頭にあると、否定形文字クラス (negated character class) を表し、角カッコ内にある文字以外に一致する。一致の対象がひとつの文字だという点は [...] でも [^...] でも変わりなく、さもなければマッチは否となる。というわけで:
/[^a]at/; # 'aat' か 'at' にはマッチしないが、 # 'bat', 'cat', '0at', '%at' などその他にはマッチ /[^0-9]/; # 数字でない文字 にマッチする /[a^]at/; # 'aat' か '^at' ならマッチ。ここでは '^' は通常文字
perl には、一般的な文字クラスに対して省略形が用意されている:
\d は 1個の数字 (a digit) のことで、下記を意味する
[0-9]
\s は 1個の空白文字 (a whitespace) のことで、下記を意味する
[\ \t\r\n\f]
\w は 1個の単語構成文字 (a word character) のことで、下記を意味
[0-9a-zA-Z_]
\D は \d の否定形であり、数字以外のあらゆる 1文字を表す
[^0-9]
\S は \s の否定形であり、空白文字以外のあらゆる文字を表す
[^\s]
\W は \w の否定形であり、単語構成文字でない (non-word) あらゆる文字を表す
[^\w]
ピリオド '.' は "\n" 以外のあらゆる文字にマッチする
省略形 \d\s\w\D\S\W は文字クラスの内外にかかわらず使える。具体例を示そう:
/\d\d:\d\d:\d\d/; # hh:mm:ss という時刻表現にマッチ /[\d\s]/; # いずれかの数字、または空白文字にマッチ /\w\W\w/; # 単語構成文字の後ろに非単語構成文字が続き、 # さらに単語構成文字が続いていればマッチ /..rt/; # 'rt' が後ろに続いた何かしらの 2文字にマッチ /end\./; # 'end.' にマッチ /end[.]/; # 同上。'end.' にマッチする
単語アンカー (word anchor) \b は単語構成文字と非単語構成文字の境目にマッチする。\w\W と \W\w のどちらの形態でも一致する:
$x = "Housecat catenates house and cat"; $x =~ /\bcat/; # 'catenates' の cat にマッチする $x =~ /cat\b/; # 'housecat' の cat にマッチする $x =~ /\bcat\b/; # 文字列の終端の 'cat' にマッチ
最後の例では、文字列の終わりが単語境界として解釈されている。
二者選択 (alternation) メタキャラクタ '|' を使用すると、複数の文字列群とのマッチを行うことができる。 dog または cat をマッチさせるには、 dog|cat という正規表現を作ってやればよい。前述したのと同様に、perl は文字列の中でマッチを満たす最も早い出現ポイントに一致しようとする。各位置毎に、perl はまずひとつ目の選択肢 dog に一致するかどうか試す。 dog に一致しなければ、perl は次の選択肢 cat に一致するかを試す。 cat もまた一致しなければマッチは失敗となり、perl は次の位置へ移る。例を幾つか示す:
"cats and dogs" =~ /cat|dog|bird/; # "cat" にマッチ "cats and dogs" =~ /dog|cat|bird/; # "cat" にマッチ
後者の正規表現例では、選択肢の最初にあるのは dog だが、文字列中で一番早く当てはまるのは cat だ。
"cats" =~ /c|ca|cat|cats/; # "c" にマッチ "cats" =~ /cats|cat|ca|c/; # "cats" にマッチ
或るひとつの文字列ポジションにおいては、正規表現マッチを満たすことのできる最初の選択肢が、一致する選択肢となる。この例では、全ての選択肢が最初の文字列ポジションでマッチするので、第一の候補がマッチする。
グループ化 (grouping) メタキャラクタ () を使うと、正規表現の一部分をひとつのユニットとして扱わせることができる。正規表現の中で部分部分をグループ化するには、それらを括弧で囲む。 house(cat|keeper) という正規表現は、後ろに cat か keeper の続く house、の意味となる。もう少し例を挙げると
/(a|b)b/; # 'ab' または 'bb' にマッチ /(^a|b)c/; # 文字列の先頭に 'ac' があるか、どこであれ 'bc' があればマッチ
/house(cat|)/; # 'housecat' か 'house' にマッチ /house(cat(s|)|)/; # 'housecats' または 'housecat' または # 'house' にマッチ。グループは入れ子 (nest) にできる。
"20" =~ /(19|20|)\d\d/; # ヌルの候補 '()\d\d' がマッチする。 # '20\d\d' は当てはまらないからだ
グループ化メタキャラクタ () には、文字列中の一致した部分を抽出する機能もある。各グループに対して一致した部分は、$1
, $2
といった特別な変数に格納されるのだ。それらは通常の変数と同様に使うことができる:
# hours, minutes, seconds の抽出 $time =~ /(\d\d):(\d\d):(\d\d)/; # hh:mm:ss の形にマッチ $hours = $1; $minutes = $2; $seconds = $3;
リストとしての文脈で扱った時、グループ化を伴った /regex/ マッチは、($1,$2,...) といった一致値のリストを返す。つまり、前記はこのように書き換えることもできる:
($hours, $minutes, $second) = ($time =~ /(\d\d):(\d\d):(\d\d)/);
正規表現の中でグループが入れ子にされていると、 $1
は一番左側にある左括弧で始まるグループ、 $2
は次の左括弧で始まるグループ ... という具合に値を受け取る。例として、或る複雑な正規表現を挙げ、一致による変数をその下に示す:
/(ab(cd|ef)((gi)|j))/; 1 2 34
$1
, $2
, ... というマッチ変数に関連したものとして、バックリファレンス (backreference) \1
, \2
, ... がある。バックリファレンスは、正規表現の内部で使用できるマッチ変数だ:
/(\w\w\w)\s\1/; # 文字列の中から 'the the' のような連続を見つけ出す
$1
, $2
, ... は正規表現の外でのみ使用でき、\1
, \2
, ... は正規表現の中でのみ使用できる。
数量子 (quantifier) ?, *, +, {} を使うと、マッチさせたい正規表現の中で特定部分の反復回数を指定することができる。数量子は、目的の文字や、文字クラス、グループの、直後に置く。それぞれ、以下の意味を持っている:
a? = 0回または 1回の 'a' にマッチする
a* = 0回以上の 'a'、つまり何回であろうとマッチする
a+ = 1回以上、つまり少なくとも 1回の 'a' にマッチする
a{n,m} = 最低 n回で最高 m回を超えなければマッチ
a{n,} = n回以上にマッチ
a{n} = ぴったり n回にマッチ
幾つか例を挙げる:
/[a-z]+\s+\d*/; # 小文字の単語、それに続いて幾つかスペースが存在し、 # (なしも含む)何回かの数字の並び、にマッチする /(\w+)\s+\1/; # 任意の長さの2単語から成る文にマッチする $year =~ /\d{2,4}/; # year が 2文字以上 4文字以下であることの確認 $year =~ /\d{4}|\d{2}/; # より手堅い照合。数字 3文字の年表記を排除する
数量子は、正規表現の成立しなくならない範囲内で、文字列のうちのなるべくたくさんの部分に一致しようとする。それを示したのが
$x = 'the cat in the hat'; $x =~ /^(.*)(at)(.*)$/; # マッチして、 # $1 = 'the cat in the h' # $2 = 'at' # $3 = '' (0回の一致)
最初の数量子 .* は、文字列のうち、正規表現の成り立つ限度内で抱えられるだけ抱え込む。 2回目の数量子 .* に当てはまる文字列はもう残っていないため、 2回目の .* は 0回にマッチすることになる。
マッチに使う演算子について、興味を惹きそうな事柄がもう少しある。下記のコード、
$pattern = 'Seuss'; while (<>) { print if /$pattern/; }
では、perl はループのあいだじゅう $pattern を毎回評価しなければならない。もし $pattern が動的に変化しないのであれば、 //o 修飾子を使って変数の代入処理を 1度だけに制限しよう。代入を全く行わせたくないのであれば、特別な区切り文字 m'' を使えばよい:
@pattern = ('Seuss'); m/@pattern/; # 'Seuss' にマッチ m'@pattern'; # 文字通りの '@pattern' にマッチ
グローバル修飾子 //g を使うと、マッチ演算子は、文字列の中で一致するものに総ざらいでマッチするようになる。スカラーとして扱った時、文字列に一致するたびに //g ジャンプが起こり、進行に応じて文字列中のポジションが捕捉さていく。ポジションは pos() 関数で読み取ったりセットしたりできる。例えば、
$x = "cat dog house"; # 単語 3つ
while ($x =~ /(\w+)/g) {
print "Word is $1, ends at position ", pos $x, "\n";
}
は
Word is cat, ends at position 3 Word is dog, ends at position 7 Word is house, ends at position 13
を表示する。
マッチが失敗するか対象の文字列が変更されると、ポジションはリセットされる。マッチが失敗してもポジションがリセットされないようにするには、 /regex/gc のように //c を加えればよい。
リストとして捉えた場合 //g は一致したグループのリストを返すが、グループ化が使われていない時には、その正規表現全体に対して一致したもののリストを返す。つまり
@words = ($x =~ /(\w+)/g); # マッチして、 # $word[0] = 'cat' # $word[1] = 'dog' # $word[2] = 'house'
検索置換は s/regex/replacement/modifiers を使って実行できる。replacement部は Perl のダブルクォート型文字列で、regex部に一致した文字列がどれも replacement で置き換えされる。 =~ はここでも文字列と s/// を結びつける働きをする。$_
に対してマッチを行う場合には $_ =~ は書かなくても構わない。ひとつでも一致があった時には s/// は行われた置換の回数を返し、一致しなかった時には偽を返す。少々の例を示そう:
$x = "Time to feed the cat!"; $x =~ s/cat/hacker/; # $x は "Time to feed the hacker!" を格納 $y = "'quoted words'"; $y =~ s/^'(.*)'$/$1/; # シングルクォートの除去。 # $y が格納しているのは "quoted words"
s/// 演算子においては、マッチ変数 $1
, $2
等々は即、replacement の中で使える。グローバル修飾子と組み合わせた s///g は、文字列中の全ての regex を探して置換する:
$x = "I batted 4 for 4"; $x =~ s/4/four/; # $x は "I batted four for 4" を格納 $x = "I batted 4 for 4"; $x =~ s/4/four/g; # $x は "I batted four for four" を格納
評価 (evaluation) 修飾子 s///e は replacement 文字列を eval(...) でラップし、一致した部分文字列が、評価結果の値 (evaluated result) で置き換えられる。幾つか例を示すと:
# 文字列中の単語を全てひっくり返す $x = "the cat in the hat"; $x =~ s/(\w+)/reverse $1/ge; # $x は "eht tac ni eht tah" を格納
# パーセンテージから10進数への変換 $x = "A 39% hit rate"; $x =~ s!(\d+)%!$1/100!e; # $x は "A 0.39 hit rate" を格納
最後の例では、 s/// が別の区切り文字 s!!! や s{}{}、さらには s{}// といったものまで使えることを示している。シングルクォート s''' が用いられた時には、regex と replacement はシングルクォートされた文字列として扱われる。
split /regex/, string は、string を部分文字列 (substrings) のリストへと分解して、そのリストを返す。どういった文字の並びを基準にして string を分解するのかを規定するのが、 regex部だ。例えば、或る文字列を単語へと分解するには
$x = "Calvin and Hobbes"; @word = split /\s+/, $x; # $word[0] = 'Calvin' # $word[1] = 'and' # $word[2] = 'Hobbes'
カンマ区切りの数値リストから値を抽出するには
$x = "1.618,2.718, 3.142"; @const = split /,\s*/, $x; # $const[0] = '1.618' # $const[1] = '2.718' # $const[2] = '3.142'
空の正規表現 // を使った場合には、文字列は一個一個の文字に分解される。正規表現がグループ化を含んでいると、生成されるリストにはグループ化によってマッチした部分文字列も含まれる:
$x = "/usr/bin"; @parts = split m!(/)!, $x; # $parts[0] = '' # $parts[1] = '/' # $parts[2] = 'usr' # $parts[3] = '/' # $parts[4] = 'bin'
$x の最初の文字が正規表現に一致したため、split はリストの最初にまず空の要素を発生させている。
Copyright (c) 2000 Mark Kvale All rights reserved.
当ドキュメントの配布は Perl本体と同一の約款で規定される。
有益な助言をしてくれた Mark-Jason Dominus, Tom Christiansen, Ilya Zakharevich, Brad Hughes, Mike Giroux に感謝する。