Study of CGI

正規表現(regular expression)

正規表現とは、文字列に対してマッチ(match)させられるパターン(テンプレート)のことです。

正規表現を使わない、文字列に対する判定は、"完全に合致する"、"合致しない"程度のものしかありませんが。正規表現を使うと"最初にAがあり次にBまたはCが続き、次にハイフォン(-)があり、5桁の数字があり文字列が終了する"といった複雑な条件に対応することが可能です。

そして、上記の"最初にAが〜"といった表現をパターン指定文字(と通常の文字)を使い表現するのが正規表現です。

正規表現の演算子には、ある特定の文字があるパターンにはまっているか否かを判定するマッチ演算子、ある特定のパターンの文字列を別の文字列に置き換える置換演算子があります。

マッチ演算子(match operator)

この場合は、マッチ演算子を使います、これは正規表現がマッチしたら真を返しそうでなければ偽を返します。

Perl で正規表現を扱うときはパターンをスラッシュ「/ ... /」で囲みます。

if ( /abc/ ) {
print $_ ;
}

この例では、変数$_のどこかに「abc」が含まれていればマッチしたといえます。

上記の例でabcのbの文字が0個以上(0も含む)含まれる文字列を探す場合は「*」(アスタリスク)を使います。

/ ab*c /#「ac」、「abc」、「abbc」、「abbbbbbc」などにマッチする

置換演算子(substitute operator)

文字列の中で正規表現とマッチした部分を捨て、置き換え文字列で置き換えます。

マッチしなければ何もしません。

s /ab*c/def/ ;

パターン

正規表現はパターンにより記述します。先の「/abc/」は「abc」を含む文字列をあらわすパターンといえます。

1文字にマッチするパターン

文字一個を正規表現の中に置くと、その文字でマッチするかテストすることができます。

それ以外にも「.」ドットでマッチをテストすると改行文字「 \n 」以外の1文字とマッチします。

たとえば/a./はa\nを除く2文字の並びにマッチします。

文字クラス(character class)

文字クラスは1対のブラケットの間に文字列を並べたもので、その中のどれか1つがあればマッチします。範囲を表すときは「-」ダッシュを置きます。

ブラケットやダッシュを判定に含めたいときは、その直前に\を置くか、リストの最後に起きます。

/ [abc] / #aかbかcのどれか一文字とマッチする
/ [ 0123456789 ] / #数字1文字にマッチ
/ [ 0-9 ] / #数字1文字にマッチ
/ [ 0-9\- ] / #数字一文字かマイナス文字1文字にマッチ
/ [ a-z0-9 ] / #英小文字1文字か数字1文字にマッチ
/ [ a-zA-Z0-9 ] / #英文字1文字か数字1文字にマッチ

文字クラスの否定(negated character class)

これは、簡単に言って文字クラスの反対、リストに含まれないものにマッチします。

使用する場合は、左ブラケットの直後に「^」キャレットを挿入すします。

/ [^abc] / #aかbかc以外のどれか一文字とマッチする
/ [^ 0-9 ] / #数字1文字以外にマッチ
/ [^ a-zA-Z0-9 ] / #英文字1文字と数字1文字以外にマッチ
/ [^ \^ ] / #キャレット以外の1文字にマッチ

あらかじめ定義されている文字クラスの略記法

正規表現を書くのに便利なようによく使う文字クラスがあらかじめ定義されています。

空白文字とは、スペース、キャリッジリターン、タブ、ラインフィード、改ページ文字のことです。

記法 等価なクラス 否定形 等価な否定クラス
/ [ \d ] / [ 0-9 ] (数字) / [ \D ] / [^ 0-9 ] (数字以外)
/ [ \w ] / [ a-zA-Z0-9_ ] (単語) / [ \W ] / [^ a-zA-Z0-9_ ](単語以外)
/ [ \s ] / [ \r\t\n\f ] (空白文字) / [ \S ] / [^ \r\t\n\f ] (空白文字以外)

グループパターン

正規表現が本当に威力を発揮するのは、「1個以上の〜」とか「5個以下の〜」といった指定を使った場合です。

並び(sequence)

例えば /abc/ は、最初がaで2文字目がbで、最後がcの順番でマッチするの意味しています。

繰り返し

すでに、「*」(アスタリスク)を使ったグループパターンを紹介しました。

上記の例でabcのbの文字が0個以上(0も含む)含まれる文字列を探す場合は「*」(アスタリスク)を、1個以上の含まれる文字列を探す場合は「+」を、1個または0個(無い)場合を探すには「?」を使います。

/ ab*c /#「ac」、「abc」、「abbc」、「abbbbbbc」などにマッチする
/ ab+c /#「abc」、「abbbc」、「abbbbbc」、「abbbbbbbc」などにマッチする
/ ab?c /#「abc」、「ac」にマッチする

そして、これらのグループパターンは、可能な限り大きな形でマッチしようとします。

$_ = "fred xxxxxxx barney" ;
s / x+ / boom / ;

例えば上のような場合、/ x+ /は、「x」にも「xx」にもマッチしますが、結果は必ず最大の「xxxxxxx」とマッチします。

汎用繰り返し指定(general multiplier)

上記の繰り返しのパターンでは、繰り返しの回数を指定することはできません。

しかし、一対のブレースの間に1個または2個の数値を記入することにより繰り返しの回数を指定することができます。

一個の数字を置いた場合は、その丁度の回数と、カンマを置いて二つ置いた場合は左が開始で右が終了になります。

また、終了を省略した場合は開始数以上となります。

/ x { 5 } / #5回の f とマッチする

/ x { 5 , 10 } / #5回以上10回以下の f とマッチする
/ x { 0 , 5 } / #5回以下の f とマッチする
/ x { 5 , } / #5回以上の f とマッチする

最短マッチ

先のように、正規表現は常に最大の文字数とマッチしようとします。

ひとつの正規表現の中に2個以上の繰り返し指定がある場合、正規表現は左から解釈されるので、まず左側に位置するものが最もたくさんの文字列とマッチし、次の繰り返しは残った部分からまた最大の文字列とマッチしようとします。

たとえば次のような場合、最初の .* は「 fff 」 ではなく「 fff B fff 」とマッチします。

$_ = "A fff B fff B fff C" ;
/ A.*B.*C / ;

この例の場合マッチ判定では特に不都合は無いが、置き換えや再利用をする場合には不都合が出てきます。

それをなくすために下記のような方法を用いることもできます。

$_ = "A fff B fff B fff C" ;
/ A.*?B.*C / ;

このように、繰り返しの指定の後に「?」を加えるとマッチは必要最小限でとどまるようになります。
この「?」は繰り返し指定「 ? 」「 + 」「 * 」「 { x , y } 」の直後に置くことができます。

バックトラック(back tracking)

正規表現のマッチは左側に位置するものが最もたくさんの文字列とマッチしようとするので、繰り返し指定が複数の場合は文字列の左側から右側へ走査しマッチしなくなると再び元に戻り前回走査しマッチしたところで次の捜査が開始されます。

このように、何重かの走査を繰り返すことをバックトラックといい、実行時間にも大きく関わってきます。最小マッチはこれを防ぐためにも一役買います。

カッコを使った記憶 

正規表現を一対のカッコ「 ( ) 」で囲むことにより文字列のうちパターンにマッチした部分を、あとで参照できるように記憶することができます。

このカッコはマッチの走査には何も影響を与えません。

記憶した文字列を呼び出すのは「 \1」のようにバックスラッシュと整数を並べて記述します。

カッコが複数存在するときは、整数の部分がカッコを左から数えての順番になります。

次のような場合、freadとbarneyの間にあるカッコが任意の一文字を記憶して、最後にもその文字が現れるというパターンを作っています。

/fread(.)barney\1/;

この場合「fread-barney-」とはマッチしますが「fread-barneyx」とはマッチしません。

選択(alternation)

複数の選択肢がある場合には「 | 」使用します。

たとえば、red、bblack、blueのどれかという場合は次のようになります。

/ red | bblack | blue /

位置指定(anchoring)

通常はパターン文字にマッチさせる場合は、左から右へと調べていき、最初にうまくいった場所でマッチします。

しかし、位置指定を使用すれば文字列の特定の位置にマッチさせることができます。

主な位置指定には次のようなものがあります。

\b 単語境界 \B 非単語境界
^ 文字列先頭 $ 文字列末尾

\b 単語境界

単語境界とは \w( [ a-zA-Z0-9_ ]) にマッチする文字と \W ([^ a-zA-Z0-9_ ] )にマッチする文字の間、あるいは \w にマッチする文字と文字列の端の間のことです。
\b を追記することによりその位置が単語境界になるものにマッチします。

/ abc\b / ;# abc にマッチし、abcd にはマッチしない

\B 非単語境界

\B を追記することによりその位置が単語境界にならないものにマッチします。

/ abc\B / ;# abcd にマッチし、abc にはマッチしない

^ 先頭文字マッチ

キャレット「^」を正規表現の先頭に記述すると次の一文字が先頭に来るものにマッチします。

ただし、キャレットは文字列の先頭になりうる場所に置かなければ、その特別な意味を失ってしまいます。(つまり、「a^」は「a」と「^」という文字になります。)

/ ^a/ ;# abcにはマッチしxabcにはマッチしない

$ 末尾文字マッチ

ドル記号「$」を正規表現の末尾に記述すると直前の一文字が末尾に来るものにマッチします。

これも、ドル記号が文字列の末尾になりうる場所に無ければその意味を失います。(スカラー変数として解釈されてしまいます)

/ c$/ ;# abcにはマッチしabcdにはマッチしない

優先順位

グループ、指定位置の優先順位  組み合わせ方によっては意味が異なってくるので正規表現にも演算子同様に優先順位があります。

以下の表は優先順位の高い順番です。

カッコ ( )、( ? : )
繰り返し指定 ?、+、*、{ m , n }、??、+?、*?、{ m , n }?
並び、位置指定 abc、^、$、\A、\Z、( ?= )、(?! )
選択 |

例を挙げると次のようになります。

FTP* FT、FTP、FTPP、FTPPP にマッチ
( FTP )* " "、FTP、FTPFTP、FTPFTPFTP にマッチ
^A | B 行の先頭の A もしくは任意の場所の B にマッチ
^( A | B ) 行の先頭にある A もしくは B にマッチ
A | BC | D A、BC、D いずれかにマッチ
( A | B ) ( C | D ) AC、AD、BC、BD いずれかにマッチ
( Song | Blue ) bird Songbird もしくはBluebird にマッチする

マッチ演算子

これまで単純なマッチ演算子は見てきました。しかし、マッチ演算子には他にも様々な機能があります。

$_以外のターゲットを選択する「=~演算子」

これまでの例では、マッチ演算子の対象を指定することはありませんんでしたので、デフォルトの変数「$_」に対して、判定をおこなっていました。

しかし、=~演算子を使うと「$_」ではなく左辺で指定した値に対してマッチするかどうか調べることができます。

左辺に指定するものは、スカラー文字列が得られる式なら何でもかまいません。右辺には正規表現をおきます。

$a = "Hello World !" ;
$a =~ / ^He / ;#真を返す
$a =~ / (.)\1 / ;#真を返す(二個の"l"にマッチ)
if ( $honda =~ / (.)\1 / ) {
処理
}

「i」-大文字小文字を無視するオプション

「i」オプションを使うとマッチを調べるときに英文字の大文字と小文字を区別しなくなります。

$a = "Hello World !" ;
$a =~ / ^H / ;#真
$a =~ / ^h / ;#偽
$a =~ / ^h / i ; # 真

デリミタ(区切り文字)について(delimiter)

文字列に「/」を文字として含めるような形で正規表現を組む場合は、「/」の前に「\」を置かなければなりません。

しかし、perlでは、「/」以外の文字を区切り文字として使用することができます。

それには、mの後に区切り文字になる文字(英数字以外)をおき、次にこれまでとおり正規表現をおき、区切り文字で締めます。

m@^/usr/local/@ 「 ! 」をデリミタにする
m#^/usr/local/#
「 # 」をデリミタにする

「/」を区切り文字として使う場合、m/ ... / の形で使うこともできます。もともと、普通のマッチ演算子の正体はm演算子です。ただ、/ を使うときだけ m の省略ができることになっているのです。

正規表現に変数展開を使用する

正規表現では最初に変数展開が行い、その他の特別な文字の解釈を行います。

したがって、その展開された文字列を使い正規表現を組み立てることができます。

$waht = "bird" ;
$sentence = "Every good bird does fly" ;
if ( $sentence =~ / \b$what\b / ) {
  print "The sentence contains the word $waht !\n" ;
}

読み出し専用の特殊変数

正規表現にカッコを使ってマッチパターンを行い成功すると、カッコの内の正規表現にマッチする部分が、 \1、\2、\3にセットされます。

そして、同時に$1、$2、$3にも同じ値がセットされます。この値は、後から$1、$2、$3を参照することで、マッチした部分の値を知ることができます。

$a = "this is a test" ;
/ (\w+) \W+ (\w+) / ;#$1 は "this"、$2 は "is" になる

また、リッチコンテキストで行っても同じ値を得ることができます。

$a = "this is a test" ;
($aa , $bb ) = / (\w+) \W+ (\w+) / ;#$aa は "this"、$bb は "is" になる

$1,2,3,,,同様読み出し専用の特殊変数には、正規表現にマッチした部分を保持する「$&」、マッチした部分より前の部分を保持する「$`」、マッチした部分より後の部分を保持する「$'」があります。


置換演算子

単純な置き換え演算子(s /old/new/)はすでに紹介しました。

この、置き換え演算子には様々なバリエーションがあります。

$_以外でマッチさせる「=~演算子」

まず、マッチ演算子のときと同様「=~演算子」を使うことで、$_以外以外に対して置き換えを行うことができます。

ただし、=~の左辺に置くものは、マッチ演算子同様スカラー値を代入できるものでなくてはなりません。

$a = "this is a test" ;
$a =~ s/test/quiz/ ; # $aはthis is a quizになる
$someplace[$here] =~ s/left/right/; #配列の要素を対象に
$d{"t"} =~ s/^/x/; #ハッシュの要素を対象に

「g」-マッチする部分をすべて置き換え対象にするオプション

通常の置き換え演算子は最初にマッチした部分だけを置換するが、「g」を最後に追記するとマッチ可能な部分全てを置換するようになります。

$a = "foot fool buffoon" ;
$a ~= s /foo/ bar /g ;# $aは"bart barl bufbarn"になる

また、大文字小文字の違いを無視する「i」オプションを同時に使うことや、置換する文字列に変数展開を使用することもできます。

また、次のように可変するものにマッチさせることもできます

$a = "this is a test" ;
$a ~= s/(\W+)/<$1>/g; # "<this> <is> <a> <test>"

$1には最初のカッコにマッチしたものがセットされます。つまりこの場合は\W+に該当するものすべてです。

また、置き換え演算子のsでもm(マッチ演算子)同様の手順で、スラッシュ以外のデリミタを使うこともできます。

また、正規表現を応用する関数にsplit関数、join関数があります。

split関数は、正規表現と文字列を引数として受け取り、文字列の中から正規表現にマッチする部分を全てを取り出し、マッチしなかった部分を順に並べてリストとして返えします。(つまりマッチした部分を区切りとして配列に変換します)

join関数は、split関数の反対の動作をしますが、正規表現はもちいません。

ポイント

  1. 正規表現はデフォルトで「/」で囲って使う。
  2. 正規表現の繰り返しは、最短マッチ(?)で適宜制御する。
  3. 正規表現中でカッコを使うと内容が\1 ・ ・ ・ 、$1 ・ ・ ・ にマッチした部分がセットされる。
  4. マッチ、置き換え演算しともに「=~」を使うことで$_以外の変数を対象にできる。
I/O Study of CGI

□新着

  • 2016/04/14
    ページ復旧
  • 2007/10/06
    Story Maker始動
  • 2007/06/13
    久々の更新
  • 2007/01/06
    logちょっとバージョンアップ
  • 2006/07/27
    ホームページのPerl 終了

□Topics

  • 2016/04/14
    サイト復旧
  • 2007/10/06
    StoryMaker始動
  • 2007/06/13
    今後にぜひご期待を!
  • 2006/06/26
    今後について
  • 2006/06/15
    環境の変化