Perlre(1) ユーザズ・マニュアル (暫定訳)

これは perlre(1) マニュアル・ページを訳そうと試みたものです。 『つれづれの正規表現』の方で正規表現の一覧がなかったので、 訳すことにしました。原本は FreeBSD 3.2-RELEASE に入っている perl 5.00503 のパッケージ中のものです。 私はさほど英語が得意なわけではありませんので、 訳の正確さについてはかなり怪しい部分が多いと言えます。 このマニュアルの訳については謙遜ではなくて 全く自信がありません。以前に訳したものに比べて 英語が格段に難しいのです。 おそらく最初のうちはかなりの頻度で更新が行われると 思います。ドキュメント末尾の RCS Id をチェックするように してください。

このバージョンの前の perl 5.004 と比較してみると正規表現に関して 大幅な改定がされているにもかかわらず、日本語で書かれたリソースが あまり見当たりませんでした。 (Jeffrey Friedl の本の訳も多少内容が古くなっている。 青いキャメルブックについては日本で出回っているものは かなり古いと思われます。) いずれ正確な訳が FreeBSD や NetBSD 等の jpman プロジェクトなどから でると思います。それまでのつなぎ程度に考えてください。

名 称

perlre
Perl の正規表現

解説

このページは Perl 言語の正規表現のシンタックスについて解説する。 マッチングオペレータのどのように正規表現を使うかとか、 それらの具体的な例については perlop マニュアルページの "Regexp Quote-Like Operators" という節の m//, s///, qr// そして ?? に関する議論を参照にされたい。

マッチングオペレータはさまざまな修飾子を持つ。 修飾子の中でも正規表現の展開に関するものは 以下にリストアップした。 修飾子でも Perl による正規表現の使われ方そのものを 変えるようなものについては、 perlop マニュアルページの "Regex Quote-Like Operators" という節の議論と "Gory details of parsing quoted constructs" という節を参考にされたい。

i

大文字小文字を区別せずにパターンマッチングを行う。

もしも use locale が有効なら、 case map はカレントロケールよりとられる。 これについては、perllocale マニュアルページを参照のこと。

m

文字列が複数行からなると仮定する。 すなわち、"^" と "$" が文字列中の 行の先頭と行の末尾にマッチするようになる。 これらは本来は文字列の真の先頭と真の末尾にしか マッチしない。

s

文字列が一行だけからなると仮定する。 すなわち、"." が改行も含む任意の一文字に マッチするようになる。これは本来は改行にはマッチしない。

/s/m 修飾子はともに "$*" の設定を変える。 すなわち、 $* の設定のいかんにかかわらず、 /s/m なしにつければ、 "^" は文字列の先頭にしかマッチせず、 "$" は文字列の末尾 (ないしは、文字列末尾の改行の直前) にしかマッチしない。 一方、/ms などとともに指定すれば、 "." は何にでもマッチするし、 "^" と "$" は 文字列中の改行コードの直後と直前に それぞれマッチするようになる。

x

空白とコメントの挿入を許し、 あなたが書いたパターンの読みやすさを高める。

これらは通常『/x 修飾子』 などと書かれる。もちろん、パターン指定の際の デリミタは『/』に限らないのだが、 通常はこのような呼称を用いる。 実は、これらの修飾子は新しい (?...) 構文を用いることで、 正規表現のなかに埋め込むことも出来る。 これらについては、以後の記述を参照されたい。

/x 修飾子自身については若干の補足説明が 必要である。 これを指定することで、正規表現のパーサに バックスラッシュでエスケープした空白や 文字クラス指定の中の空白を除いては あらゆる空白を無視するように指示する。 これによって、自分で書いた正規表現を より読みやすい部分に分けることが出来る。 『#』文字はまた コメントの開始文字として扱われるようになる。 これはまったく通常の perl のコードに於けるそれと かわらない。 これはまた、もしも文字通りの 『#』や空白が必要ならば、 エスケープするか、 8 進または 16 進数によるコード指定を しなければならない。 (ただし、文字クラス指定の中では必要ない。 逆に、これは /x は 文字クラスの指定には影響を及ぼさないことを意味する。) これらの機能によって perl の正規表現は 可読性を求める方向に向かったと言っても良い。 なお、コメントの中にパターン区切りを入れないように 注意すること。 perl にはあなたがどこでパターンを終了させているか 知る術がないのである。 perlop ページの C コメントの除去コードの 例を参照のこと。

正規表現

パターンマッチングで使われるパターンは ヴァージョン 8 regex ルーチンで提供されているものである。 (実際には、ルーチンは Henry Spencer の再配布可能な V8 ルーチンを 実装し直したものからとっている。もっとも、オリジナルからは だいぶかけ離れているが。) 詳しいことは Version 8 Regular Expressions という節を 参照にされたい。

ことに次のメタキャラクタは 標準的な egrep 風の意味を持っている :

\
次のメタキャラクタをクォートする。 (つまり後続のメタキャラクタを文字通り解釈させる。)
^
行の先頭にマッチする。
.
改行文字を除く任意の文字にマッチする。
$
行の末尾にマッチする。 (あるいは、行の末尾の改行文字の直前)
|
一つのパターンの選択を表す。
()
グルーピング
[]
文字クラス

デフォルトでは "^" は 文字列の先頭にのみマッチするように保障されている。 また "$" は文字列末尾 (ないしは末尾にある改行の直前)にのみマッチする。 Perl は文字列が一行のみからなると仮定して ある種の最適化を行っている。 文字列中の改行は "^" や "$" ではマッチしない。 とはいえ、あなたは文字列を 複数行からなるものとして扱いたい時もあるだろう。 例えば、"^" は改行文字の直後に "$" は改行文字の直前に マッチさせたいなど…。 多少のオーバヘッドを覚悟すれば、 /m 修飾子の指定でこれを行うことが出来る。 (古いバージョンではこれを $* をセットすることで行っていたが、 現在ではそうしていない。) (訳注 : 原文 "Older programs did this by setting $*, but this practice is now deprecated." 教会での礼拝に関する用語が使われている。 この辺は推測で訳した。)

複数行の置換を行うにあたって、 "." は決して改行文字にはマッチしない。 ただし、/s 修飾子を使えば 話は別である。 これは実際に文字列が複数行からなるにしても あたかも、文字列が一行だけからなるように処理するように Perl に指示を与える。 /s 修飾子は $* の設定も変える。 あなたが、(行儀の悪い)この変数の設定を変更する 古いコードを使っている場合にこれは有効である。(訳注 : ???)

次の標準的な量指定子が認識される :

*
0 回以上の繰り返しにマッチする。
+
1 回以上の繰り返しにマッチする。
?
1 回または 0 回の繰り返しにマッチする。
{n}
過不足なく n 回の繰り返しに マッチする。
{n,}
n 回以上の繰り返しにマッチする。
{n,m}
n 回以上 m 以下の繰り返しにマッチする。

(カーリブラケットが他のコンテキストで 現れた場合には、文字通りの解釈が行われる。) "*" 指定子は {0,} と等価である。 また "+" は {1,} に、 "?" は {0,1} に 等価である。 n, m には制限がある。 perl がビルドされた時の整数の限界値以下の 整数でなければならない。 大部分のプラットフォームではこの限界は 通常 32766 である。 実際の限界値は次のコードを実行した時の エラーメッセージから分かる。

    $_ **= $_ , / {$_} / for 2 .. 42;

デフォルトでは量指定されたサブパターンは "greedy" である。すなわち、可能な限り長いパターンに マッチしようとする。(特定のマッチ開始点を与えた場合。) これはマッチする余地がある限りマッチし続けるということである。 可能な限り短いパターンにマッチさせるためには 量指定子に "?" 修飾子をつける。 これは意味は変わらないが、マッチのための『どん欲さ』に 影響を与える。

*?
0 回以上の繰り返しにマッチする。
+?
1 回以上の繰り返しにマッチする。
??
1 回または 0 回の繰り返しにマッチする。
{n}?
過不足なく n 回の繰り返しに マッチする。
{n,}?
n 回以上の繰り返しにマッチする。
{n,m}?
n 回以上 m 以下の繰り返しにマッチする。

パターンはダブルクォートされたものとして処理されるので、 次のようなものも使うことが出来る。

\t
タブ (HT, TAB)
\n
改行文字 (LF, NL)
\r
復帰 (CR)
\f
フォームフィード (FF)
\a
アラーム (ベル) (BEL)
\e
エスケープ (troff を思い出せ。) (ESC)
\033
8 進数 (PDP-11 を思い出せ。)
\x1B
16 進数
\c[
コントロール文字
\l
次の文字を小文字に (vi を思い出せ。)
\u
次の文字を大文字に (vi を思い出せ。)
\L
\E まで小文字に (vi を思い出せ。)
\U
\E まで大文字に (vi を思い出せ。)
\E
大文字・小文字の変換の終了 (vi を思い出せ。)
\Q
メタキャラクタの意味を \E が現れるまでキャンセルする。

もしも use locale が有効になっているのなら、 \l, \L, \u, \U などが使うケースマップはカレントロケールからとられる。 perllocale マニュアルページを参照されたい。

\Q シーケンスには文字通りの $ やら @ を含めることが出来ない。 エスケープされていない。 $@ は対応する変数に展開される。 他方、エスケープすることで、マッチするべきリテラル文字列 \$ になる。 恐らく m/\Quser\E\@\Qhost/ などといった書き方が必要になるだろう。

さらに Perl は次を定義している。

\w
単語を構成する文字を表す。(英数字と "_")
\W
単語を構成する文字以外の文字
\s
空白文字
\S
空白文字以外の文字
\d
数字
\D
数字以外の文字

\w は英数字一文字にマッチする。 単語全体にマッチするわけではない。 単語全体にマッチさせるには \w+ などと指定する必要があるだろう。 もしも use locale が有効になっているのなら、 \w が生成するアルファベット文字のリストは カレント・ロケールからとられる。 これについては、 perllocale マニュアルページを参照されたい。 文字クラス指定の中でも \w, \W, \s, \S, \d, \D を使うことが出来る。 (ただし、範囲指定の開始と終りには使えない。)

Perl は次のような幅ゼロの assertion を定義している。

\b
単語の境界にマッチ
\B
単語の境界でない箇所にマッチ
\A
文字列の先頭にのみマッチ
\Z
文字列の末尾ないしは末尾の改行の直前にのみマッチ
\z
文字列の末尾にのみマッチ
\G
直前の m//g が離れた箇所にマッチ (/g とともにのみ動作する。)

単語境界 (\b) は 二文字の間のスポットにマッチする。 この場合には、片方が \w で もう片方が \W となっている ようなものである。さらに、この場合、 文字列の開始および末尾は 文字クラス \W に属するものとみなしている。 (文字クラス中では、\b はバックスペースとして 解釈される。) \A, \Z などはそれぞれ "^", "$" などとまったく同じである。 ただし、/m 修飾子を使っても複数回マッチすることはない。 一方、"^" や "$" は文字列内の行の境界に 出現のごとにマッチする。 文字列の末尾に真にマッチさせるには \z を使う。 こうすると末尾の改行を無視したりしない。 \G assertion はグローバルマッチ (m//g) をチェインさせるのに使う。 これは perlop マニュアルページの "Regex Quote-Like Operators" という節に書いてある。

これは lex ライクなスキャナを書く際には便利である。 あなたが沢山のマッチさせなければならないパターンを持っていて、 引続き後続の文字列にマッチさせるにはこれが便利である。 \G が実際にマッチしたポジションは pos() 関数を左辺値として使うことで変えることが出来る。 詳しいことは perlfunc マニュアルページの pos 関数の 部分を参考にされたい。

かっこで括った構文が使われた時には、 \<digit>digit 番目の部分文字列にマッチする。 パターンの外側では "\" の代わりに "$" が 常に用いられる。 \<digit> は現在のパターンの外側では稀にしか動作しない。 あまり信頼するべきものではない。以下の『警告』のセクションを 参考にされたい。) $<digit> (そして $`, $&, $') はブロックの終了や eval される文字列のスコープを 次の最初にマッチが成功したパターンマッチングまで広げてしまう。 もしも、単純にグルーピングのためだけに(例えば、選択肢の提示のみにつかうなど) 使い、パターンのセーブが不要なら、 (?:...) を使えば良い。

かっこは使いたいだけ使える。 もしも、9 個以上の部分列があるなら $10, $11 などが使える。 パターン中で、もしも十分な数の後方参照があらかじめあるのなら、 \10\11 はそれに対応する。 (これらが現れるまでに 10 対のかっこがないといけない。) さもなければ、従来との互換性のために \10\010 (すなわちバックスペース)に、 \11\011 (タブ)に対応する 文字コードを表すようになる。 (ただし、\1 から \9 までは後方参照のみに 用いられる。)

$+ は最後のかっこにマッチしたものにマッチする。 $& はマッチした文字列全体を返す。 ( $0 は同じものを返すために使われていたが、 もはや使われない。) $` はマッチした文字列の前のすべての文字列を返す。 $' はマッチした文字列の後のすべての文字列を返す。 例をあげると :

s/^([^ ]*) *([^ ]*)/$2 $1/;     # swap first two words

if (/Time: (..):(..):(..)/) {
    $hours = $1;
    $minutes = $2;
    $seconds = $3;
}

一旦 perl が $&, $`, $' をプログラムのどこかであなたが使っているのを認識したら、 各パターンマッチごとにそれが必要とされると仮定される。(訳注 : ???) これはプログラムのスピードを劇的に遅くする。 同じことは $1, $2 などの使用についてもあてはまる。 従って、かっこでの捕捉を含むようなパターンごとに上での述べたのと 同じだけの代価を支払っていることになる。 しかし、もしも決して $& などをスクリプト中で使わないのであれば、 捕捉を行わないパターンはこの代償を払わないですむ。 従って、可能な限り $&, $', $` の使用は避けた方が良い。 しかし、もしも使わざるを得ない(あるアルゴリズムはこれらを 確実に期待する。)のであり、一旦使ってしまったのなら、 あとは思うままに使って構わない。既に代価は支払ったのだから。 5.005 に関する限り $& は他のものに比べて さほどコストが高くなるわけではない。

Perl ではバックスラッシュのついたメタキャラクタは 英数字のものに限定される。例えば、 \b, \w, \n 等である。 他の種類の正規表現とは違って、英数字でない文字に バックスラッシュのついたメタキャラクタは存在しない。 したがって、 \\, \(, \), \<, \>, \{, \} などといったものは常にリテラルとして解釈される。 これはかって正規表現のメタキャラクタの特別な意味を 取り除くために使われていたありふれた常套句である。 英数字ではない文字をクォートするには単純に :

    $pattern =~ s/(\W)/\\$1/g;

現在では 同じことをするのには quotemeta() 関数を用いるか、 \Q エスケープシーケンスを使うのがよりありふれた方法といえる。 次の例のようにすると良い :

    /$unquoted\Q$quoted\E$unquoted/

Perl は正規表現を拡張するための一貫したシンタックスを定義している。 シンタックスは疑問符をともなったかっこの対である。 (これは古いバージョンでは文法的なエラーになる。) 疑問符の後の文字が拡張された機能を提供する。 いくつかの拡張は既にサポートされている。

(?#text)

コメントである。text は無視される。 もし /x スイッチが自由な空白の解釈のためにセットされているのなら、 単純に # を使えば良い。 perl は閉じかっこ ) をみると ただちにコメントを閉じるようになっていることに注意。 従って、文字通りの ) をコメント内に書く方法は存在しない。

(?:pattern)
(?imsx-imsx:pattern)

これはクラスタリングのために存在し、キャプチャリングは行わない。 すなわち、"()" のような部分表現のグルーピングを行うが、 "()" が行うような後方参照を生成しない。 従って、

  @fields = split(/\b(?:a|b|c)\b/)

  @fields = split(/\b(a|b|c)\b/)

と同じである。 しかし、それ以上の余計なことをしない。

?: の間の文字は 修飾子のように振舞う。 詳しいことは後述の (?imsx-imsx) を参考のこと。 特に、

 /(?s-i:more.*than).*million/i

をちゃんと書けば、

 /(?:(?s-i)more.*than).*million/i

に等価である。

(?=pattern)

幅ゼロの前方宣言である。 例えば、 /\w+(?=\t)/ はタブが後続する単語にマッチする。 しかし、タブ自体は $& に含まれない。

(?!pattern)

幅ゼロの反対の意味の前方宣言である。 例えば、 /foo(?!bar)/ は "bar" が後続しない "foo" にマッチする。 しかしながら、前方宣言と後方宣言は異なることに注意すること。 これを後方宣言に使うことは出来ない。

もしも、"foo" が先行しない "bar" を サーチするのなら、 /(?!foo)bar/ ではあなたの期待通りには動作しない。 これは (?!foo) が次のものが "foo" ではないといっているだけだからで、 さらにそれ自体が "foo" ではなく単純に "bar" であることしかいっていない。 だから、 "foobar" は上のパターンにマッチしてしまう。 このためには、おそらく /(?!foo)...bar/ 等としなければならないだろう。 ところでいま『等と』といった。 これはあなたがサーチしたい "bar" が先行する三文字を持たないこともあり得るからである。 このようなケースをカバーするには、 /(?:(?!foo)...|^.{0,2})bar/ などとすれば良い。 あるいは

    if (/bar/ && $` !~ /foo$/)

等とする方がまだ簡単かも知れない。

後方宣言については、以下の記述を参考のこと。

(?<=pattern)

幅ゼロの肯定的な意味の後方宣言。例えば、 /(?<=\t)\w+/ はタブに続く単語にマッチする。 ただし、タブは $& には含まれない。これは固定長の後方宣言に対してのみ動作する。

(?<!pattern)

幅ゼロの反対の意味の後方宣言。 例えば、 /(?<!bar)foo/ は "bar" に続かない "foo" にマッチする。 これも固定長の後方宣言に対してのみ動作する。

(?{ code })

実験的な幅ゼロの Perl コードを eval する宣言である。 常に成功する。 コードの結果は展開されない。 現在のところ、どこでコードが終了するかはいくぶん複雑になっている。

コードは次の意味で固有のスコープを持つ : もしも宣言が backtracked ( Backtracking の節を参考のこと ) ならすべての局所化された後のすべての変更は undo される。 したがって

$_ = 'a' x 8;
m<
  (?{ $cnt = 0 })                    # Initialize $cnt.
  (
    a
    (?{
        local $cnt = $cnt + 1;       # Update $cnt, backtracking-safe.
    })
  )*
  aaaa
  (?{ $res = $cnt })                 # On success copy to non-localized
                                     # location.
 >x;

$res = 4 とセットする。 マッチしたあとは $cnt はグローバルにセットされた 0 を 返すことに注意すること。 local で制限されたスコープは元に戻るからである。

この宣言は (?(condition)yes-pattern) スイッチとしても使える。 もしも、そのように使わないなら、eval の結果は 変数 $^R に格納される。 これは直ちに実行されるので、 $^R は同一の正規表現中の他の (?{ code }) 宣言の中で使える。

上の $^R への値の代入は固有に局所化されている。 もしも宣言が backtracked なら、 $^R の古い値が保存される。

セキュリティの観点から、 use re 'eval' プラグマが使用されていない限りは 正規表現が実行時に展開される変数を含む場合には この構文の使用は許可されない。 ( re マニュアルページを参考のこと ) さもなければ、変数は qr() の結果を 含んでいる。( perlop マニュアルページの qr/STRING/imosx のセクションを参考のこと)

この制限は汚染チェックなしに広く使われている(疑問の多い) 構文

$re = <>;
chomp $re;
$string =~ /$re/;

のためである。 上のようなコードはセキュリティの観点から歓迎されていないにも かかわらず、 (?{}) が導入された時に、存在するスクリプトに新しい セキュリティホールを加えるということで、 悪いものと見なされてしまった。 (訳注 : スクリプトはそのままで perl 自体が差し替えられた時に このセキュリティホールが深刻な問題となるため。従って、 明示的なチェックを経ないとこの構文は使えない。 しかし、本来的には上のような正規表現を受け取って eval するようなコード自体に問題があるといえる。 にもかかわらず、そういう問題のあるコードではなくて perl の機能である (?{}) に罪がなすりつけられた 状態になったことを嘆いているのである。 この解釈は怪しいかも知れない。読者の御教示を乞う。)

注意: 上のような安全でないスクリプトの断片の汚染チェックなしの 使用は きびしい非難の対象とされるべきである。 use re 'eval' は汚染チェックを停止させない。 だから、上のような断片中の $re(?{}) と共に使うには use re 'eval' と汚染除去の両方を 行わなければならない。

(?>pattern)

『独立した』部分表現。 スタンドアロンなパターンで与えられた位置にアンカーされ なおかつ、それ自体である時にマッチする。

例えば、 ^(?>a*)ab は決してマッチしない。 つまり (?>a*) (上のように文字列の先頭にアンカーされている) は文字列の先頭にあるすべてもじが a であるような文字列に一致するので、 これは ab のための a を残さない。 一方、 a*aba+b と同じにマッチする。 というのも後続の文字列 ab によって a* は影響を受けるからだ。 ( バックトラッキングの節を参考のこと ) とくに a*aba* はスタンドアロンの a* に 比べて少ない文字でマッチする。 これは末尾のマッチがあるからだ。

(?>pattern) と似たような効果は

(?=(pattern))\1

によっても得ることが出来る。 前方宣言は『論理的』コンテクストにあるために スタンドアロンの a+ と同じ部分文字列に マッチするからだ。 つづく \1 はマッチした文字列を食うために (?>...) と同じような幅ゼロの宣言を作る。 (両者の違いは後者はグループの捕捉を用いていると言うことである。 従って、残りの正規表現で後方参照の順序のシフトが起こる。 (訳注 : ???)

この構文は『永久』マッチの最適化に役立つ。 これはバックトラッキングを引き起こさないからだ。 (バックトラッキングのセクションを参考のこと。)

m{ \(
       (
         [^()]+
       |
         \( [^()]* \)
       )+
    \)
}x

これは 2 レベル以下の入れ子のかっこの対には能率的にマッチする。 しかし、そのようなグループがなければ 無限に長い文字列にマッチしてしまう。 これは長い文字列を部分文字列に分解する方法があまりにも 多く存在するためである。 これは (.+)+ が何をするのかを考えて見れば良い。 これは上のパターンのサブパターンと同じである。 例えば、上のパターンが ((()aaaaaaaaaaaaaaaaaa にマッチしないということがわかるのに数秒を要する。 他の文字があれば各文字ごとにこの時間は倍になっていく。 この指数関数的なパフォーマンスはあなたのプログラムが ハングアップしたのではないかと思わせるぐらいだ。

しかし、ちょっと修正して

m{ \(
      (
        (?> [^()]+ )
       |
        \( [^()]* \)
       )+
    \)
 }x

として見る。これは (?>...) を使っているが、前のコードにマッチするのと全く同じものに マッチする。 (これを自分で確かめるのは良い練習になるだろう) しかし、1000000 個の a を含む似たような文字列に対して 4 倍程度の時間で終了する。 ただし、いまのところこのパターンを使うと -w オプションを指定した状態で、 "matches the null string many times" というメッセージの 引金になるので注意すること。

(?> [^()]+) のような単純なグループに関しては [^()]+ (?! [^()] ) などのような反対の意味の前方宣言を使った場合に比べて 比較できる程の効率を得られる。 これは 1000000 個の a をもつ文字列についても 4 倍程度遅かっただけである。 (訳注 : このあたり誤訳かも知れない。)

(?(condition)yes-pattern|no-pattern)
(?(condition)yes-pattern)

条件つき表現である。 (condition) はかっこで括られた整数 (もしも対応するかっこが対応していれば、ただしい) か、 前方宣言、後方宣言、eval つき宣言でないといけない。

例えば、

m{ ( \( )?
   [^()]+
   (?(1) \) )
}x

はかっこの対応がとれていない文字列に対応する。 ただし、かっこ自体もマッチする文字列に含まれる。

(?imsx-imsx)

パターンマッチ修飾子の指定。これは表のどこかで指定された 特定のパターンに対して便利である。 例えば、ある欄は大文字小文字を区別するが、 他の欄は区別しない様な場合には便利である。 大文字小文字を区別しないのなら、パターンの先頭に 単に (?i) を付け加えれば良い。 例えば、

$pattern = "boobar";
if ( /$pattern/i ) { }

# more flexible:

$pattern = "(?i)foobar";
if ( /$pattern/ ) { }

文字の後の - はスイッチをオフにする。

修飾子はかっこで括られたグループ内に局所化される。 例えば、

( (?i) blah ) \s+ \1

(上の場合には x 修飾子の指定を仮定している。 そしてグループの外には i 修飾子の指定が ないということも仮定している。) は単語 blah の大文字小文字を含めた意味での 繰り返しにマッチする。

疑問符は以上の説明と最小マッチング構文のために 選ばれた。その理由は (1) 疑問符は古い正規表現では使われるのがまれなため。 (2) それがあれば、あなたは一旦立ち止まって 何がなされているかを正確に知ろうと疑問を発するべきだからである。 まあ、ちょっとした心理学の応用である…。

バックトラッキング

正規表現のマッチの基本的な特徴はバックトラッキングという 概念を含むことである。 これは現在(必要なら) すべての量指定子を伴う 正規表現で使われている。つまり、 *, *?, +, +?, {n,m}, {n,m}? 等である。

正規表現がマッチするには、正規表現全体がマッチしなければならない。 決してその部分がマッチするわけではないのである。 従って、もしもパターンの始めに量指定された正規表現があり そのあとにマッチしないパターンを含んでいる場合には マッチングエンジンは最初の正規表現に戻り再計算する。 これがバックトラッキングといわれるゆえんである。

例を挙げる。例えば、文字列 "Food is on the foo table." の中の "foo" という文字列を 見つけ出したいとする。

$_ = "Food is on the foo table.";
if ( /\b(foo)\s+(\w+)/i ) {
    print "$2 follows $1.\n";
}

マッチングがはじまった時、正規表現の最初の部分 (\b(foo)) が正しいマッチングの可能性のある文字列の先頭に注目する。 そして、 $1 に "Foo" を格納する。 しかし、すぐにマッチングエンジンは "Foo" の直後には空白がないことを発見する。 これは間違いであることを認識して、一文字進めて最初からやり直す。 これが、次の "foo" まで続けられる。 この時に完全に正規表現がマッチする。 そして、期待した通り "table follows foo." という 出力を得る。

時々、最小マッチングがかなりの助けとなる。 いま "foo" と "bar" との間にある すべてのものにマッチさせたいとする。 最初は次のように書くだろう。

$_ =  "The food is under the bar in the barn.";
if ( /foo(.*)bar/ ) {
    print "got <$1>\n";
}

これは期待に反して

got <d is under the bar in the > 

と出力する。 これは .* が貪欲なためである。 したがって、最初の "foo" と最後の "bar" の間にあるすべてを得ることになる。 この場合には、最小マッチングを使い "foo" と次に来る最初の "bar" の間のテキストを得るようにすれば良い。 だから

  if ( /foo(.*?)bar/ ) { print "got <$1>\n" }
got <d is under the >

もう一つ例がある。 文字列末尾の数字のならびにマッチさせたいとする。 で、マッチした部分の前の文字列を保存したいとする。 あなたはきっと次のように書くだろう。

$_ = "I have 2 numbers: 53147";
if ( /(.*)(\d*)/ ) {                                # Wrong!
    print "Beginning is <$1>, number is <$2>.\n";
}

これはまったくうまく動作しない。 .* が貪欲なために、文字列全体を食い尽くしてしまうからだ。 更に、 \d* が空な文字列にマッチしてしまうために。 全体としてマッチは成功してしまう。

Beginning is <I have 2 numbers: 53147>, number is <>.

類似の例はいくらでもある。次の例では ほとんどがうまく動作しない。

$_ = "I have 2 numbers: 53147";
@pats = qw{
    (.*)(\d*)
    (.*)(\d+)
    (.*?)(\d*)
    (.*?)(\d+)
    (.*)(\d+)$
    (.*?)(\d+)$
    (.*)\b(\d+)$
    (.*\D)(\d+)$
};

for $pat (@pats) {
    printf "%-12s ", $pat;
     if ( /$pat/ ) {
        print "<$1> <$2>\n";
    } else {
        print "FAIL\n";
    }
}

これは次のような出力をする。

(.*)(\d*)    <I have 2 numbers: 53147> <>
(.*)(\d+)    <I have 2 numbers: 5314> <7>
(.*?)(\d*)   <> <>
(.*?)(\d+)   <I have > <2>
(.*)(\d+)$   <I have 2 numbers: 5314> <7>
(.*?)(\d+)$  <I have 2 numbers: > <53147>
(.*)\b(\d+)$ <I have 2 numbers: > <53147>
(.*\D)(\d+)$ <I have 2 numbers: > <53147>

見ての通りこれはちょっとトリッキーかも知れない。 ただ、正規表現は単なるマッチが成功するための条件の集合である ということを理解することが大切である。 特定の文字列に対して、マッチを成功させるための 条件の定義はいくつかあるかも知れない。 で、もしもいくつかあるのなら、 あなたはどのような表現を書くのがあなたのやりたいことを実現するのかを 知るためにバックトラッキングについて知る必要があるということである。

前方宣言とそれの反対を使う場合には さらにトリッキーになって来る。 いま、"123" がつづかない数字でない文字列を 探したいとしよう。 おそらく次のように書くだろう。

$_ = "ABC123";
if ( /^\D*(?!123)/ ) {              # Wrong!
    print "Yup, no 123 in $_\n";
}

しかしこれはマッチしない。少なくとも、あなたの希望通りの結果には ならない。 これは単純に文字列には 123 がないということしか いっていない。 なぜ、大部分の期待に反する結果を生むかのいい説明が ある。

$x = 'ABC123' ;
$y = 'ABC445' ;

print "1: got $1\n" if $x =~ /^(ABC)(?!123)/ ;
print "2: got $1\n" if $y =~ /^(ABC)(?!123)/ ;

print "3: got $1\n" if $x =~ /^(\D*)(?!123)/ ;
print "4: got $1\n" if $y =~ /^(\D*)(?!123)/ ;

これは次のような出力を得る。

2: got ABC
3: got AB
4: got ABC

あなたはおそらくテスト 3 も失敗するだろうと思ったかも知れない。 というのも、これはテスト 1 を一般化したようなものだからだ。 重要な違いはテスト 3 のほうは量指定子 (\D*) を含むということである。 従って、バックトラッキングの恩恵に預れる。 一方テスト 1 には量指定子がない。 (訳注 : 次の文は訳せなかった。 What's happening is that you've asked "Is it true that at the start of $x, following 0 or more non- digits, you have something that's not 123?") もしもパターンマッチエンジンが (\D*) を "ABC" にまで広げたら、パターン全体がマッチに失敗する。 最初にエンジンは (\D*) を "ABC" まで広げてマッチさせる。 それから、 (?!123) を "123" にマッチさせようとするが、もちろんこれは失敗する。 しかし、正規表現中で量指定子 (\D*) が使われているために、 エンジンはバックトラックできる。 そして、期待とは違った形で正規表現全体を マッチさせることに成功するのである。

パターンは本当にマッチに成功しないといけない。 従って、それは標準的なバックオフアンドリトライを 使い、 (\D*) を今度は "AB" に展開する。 この時、本当に "AB" のあとには "123" ではないものが続くことになる。 それは実際には "C123" であってこれでマッチに成功する。

これを宣言と否定を使って扱うことが出来る。 $1 の最初の部分が数字が続くもので、 なおかつ、それは "123" でないという風にいえば良いのである。 前方宣言は幅ゼロの表現であることを思い出すこと。 それは単純に先を見るだけである。 しかし、マッチする文字列を消費しない。 (訳注 : マッチの開始ポイントを先に進めない。) だからこのように書き換えれば、期待したものが得られるはずである。 すなわち、テスト 5 は失敗し、テスト 6 は成功する。

print "5: got $1\n" if $x =~ /^(\D*)(?=\d)(?!123)/ ;
print "6: got $1\n" if $y =~ /^(\D*)(?=\d)(?!123)/ ;

6: got ABC

いいかえると、二つの幅ゼロの宣言があたかも 一緒に働くのである。 これはビルトイン宣言の使い方と変わらない。 /^$/ は行の先頭であってなおかつ行の末尾であるということが 同時に起こっている場合でないとマッチしない。 根底にある真実は正規表現では明示的に縦棒をつかって OR を指定しない限り位置の指定は常に AND を意味するということだ。 /ab/ が意味するのは "a" にマッチしなおかつそれから "b" にマッチするということである。 ただこの場合にはマッチは異なる位置に対して試みられるということである。 これは "a" が幅ゼロの宣言ではなく幅 1 の宣言だからである。

ちょっと警告: あまりに複雑な表現は指数関数的な時間を消費することがある。 これはマッチを試みるための可能な候補の数が膨大なものになるからである。 例えば、

/((a{0,5}){0,5}){0,5}/

はかなりの時間を消費する。 さらにもしも、 {0,5} のかわりに * なんかを使おうものなら、文字通り永遠に終らない。 さもなければ、スタックを使い尽くすまで動作するだろう。

こういった怪物を最適化するための強力なツールが 『独立した』グループである。これはバックトラッキングを 起こさない。 (これは (?>pattern) の記述を参考のこと) また、幅ゼロの前方・後方宣言も末尾のマッチの際に バックトラッキングを生じない。 なぜなら、それらは『論理』コンテキストにあるからだ。 それらがマッチするか否かが問題になるだけである。 前方宣言は次のマッチに影響をおよぼすという副作用をもつ この例については (?>pattern) の記述を参考のこと。

ヴァージョン 8 正規表現

ヴァージョン 8 のレギュラーな regex ルーチンにあまり詳しくない 人のための説明である。

一文字の文字はそれ自身にマッチする。ただし、 すでにあるいはこれから述べるような特別な意味をもつ メタキャラクタは別である。 文字の前にバックスラッシュ "\" を つけることで、メタキャラクタは通常の文字通りの意味を 持つようになる。 (例えば、 "\." は任意の文字ではなくて "." にマッチするようになる。 また、 "\\" は "\" にマッチする。) 一連の文字の並びはターゲットの文字列中の 同じ文字の同じ並びにマッチする。 従って、パターン blurfl は ターゲットの文字列中の "blurfl" にマッチする。

文字のリストを [] で括ることで、 文字クラスの指定を行える。これはリスト中の文字の中の 任意の一文字にマッチする。 もしも "[" の直後の最初の文字が "^" なら クラスはリストにない文字のクラスにマッチする。 リスト中では "-" は範囲を指定するために用いる。 従って、 a-z は "a" から "z" までのすべての文字をあらわすことになる。 もしも、 "-" 自体を文字クラスのメンバにしたいのなら、 リストの最初か最後かにそれをおくこと。 ないしはバックスラッシュでエスケープすること。 ([-az], [az-], [a\-z] はいずれも三文字からなる同一のクラスをあらわす。 これらすべて、26 文字からなるクラスの [a-z] とは異なる。)

あらゆる範囲指定は文字セット間での移植上の問題を 起こすことに注意すること。同一の文字セットを 使っている環境であっても思いがけない結果を生むこともある。 原則としてはじまりと終りの大文字小文字が同じアルファベットであるとか 数字であるとかが良い (例 : [a-e], [A-E], [0-9] )。 それ以外は安全ではない。 疑わしい場合には全部の文字を書き出した方が良い。

文字の指定には C 言語で使うようなメタキャラクタシンタックスも 使える。 "\n" は改行に "\r" は復帰に、そして "\f" はフォームフィードをあらわす。 より一般的に、 "\nnn" で nnn が 8 進数をあらわす数字の列なら、マッチする文字の ASCII コードは nnn である。 同様に、 "\xnn" は 16 進数をあらわす。 これは ASCII コード nn の文字にマッチする。 "\cx" はコントロール文字をあらわす。すなわち、これは "Cotrol-x" に対応する文字にマッチする。 最後に、"." は /s フラグが指定されていない限り \n をのぞく一文字にマッチする。

"|" を使うことで、一連のパターンの選択を 指定できる。 従って、 fee|fie|foe は "fee", "fie", "foe" のいずれかにマッチする。 (つまり f(e|i|o)e と同じ)。 最初の選択肢は最後に出現した パターン区切りの記号 "(", "[" ないしは パターンのはじまりから最初の "|" までになる。 最後の選択肢は 最後の "|" から次のパターン区切り記号までになる。 従って、選択肢をかっこの中にいれるというのは 開始と終了に関する混乱を最低限にするための 広く行われている処置である。 (訳注 : この記述は結合の優先度をさりげなく示唆していることに 注意。)

選択は左から右へ行われる。 従って選ばれた最初の選択肢が正規表現全体をマッチさせる。 これは選択肢は貪欲ではないことを意味する。 例えば、 foo|foot が "barefoot" にマッチする時、 "foo" のみがマッチする。これでマッチ全体が成功してしまう。 (これは重要ではないように思われるかも知れないが、 マッチしたテキストをかっこをつかって捕捉する場合には 重要になる。)

また、"|" はブラケットの中では 文字通りに解釈されることに注意すること。 従って、 [fee|fie|foe][feio|] と等価である。

パターン中では部分パターンをかっこで括って あとでの参照に使うことが出来る。 そしてあとで、メタキャラクタ \n を使うことで、(n は数字をあらわす。 アルファベットの n ではない。) パターン中で使うことも出来る。 サブパターンは 左から右への左開きかっこの順番に基づいて番号が振られていく。 後方参照は既に評価された実際にマッチしたサブパターンに マッチする。決して、ルールにマッチするわけではない。 ゆえに、 (0|0x)\d*\s\1\d* は "0x1234 0x4321" にはマッチするが、 "0x1234 01234" にはマッチしない。 サブパターン 1 は実際には "0x" にマッチしてしまっている ので、ルール 0|0x が保証しているように 潜在的に 0 にマッチしたとしてもこの場合には マッチしないのである。

\1 と $1 に関する注意

ある人たちは次のようなコードを書きすぎる

$pattern =~ s/(\W)/\\\1/g;

この古めかしい sed 中毒者のショックを避けるためのコードは ちょっと慣れるには汚すぎる。 Perl 風の考え方をすれば、s/// の右半分は ダブルクォートされた文字列と同じである。そして、 \1 は通常 control-A を意味するコードに展開される。 習慣的な \1 の UNIX の意味は s/// の ために違った使われ方をしている。 しかしながら、こうする習慣になれてしまったのなら、 /e 修飾子をつけた時にトラブルにあうことだろう。 (訳注 : この辺訳はまったくでたらめ。)

s/(\d+)/ \1 + 1 /eg;        # causes warning under -w

さもなければ、次のようにしたとする。

s/(\d+)/\1000/;

すると \{1}000 などとしても、表記のあいまさを取り除くことは 出来ない。その一方で、${1}000 とすれば あいまいさを取り除ける。 基本的に変数展開の操作が後方参照の操作を混乱させることはない。 しかし s/// の左半分ではそれらは たしかに全く違った意味を持っている。

ながさ 0 の部分文字列の繰り返し

警告: この先には難しい内容が多い。書き直しが必要かも (訳注 : 上はオリジナルのマニュアルを書いた人のメモ。 このセクションの訳は全滅。)

正規表現は簡潔でパワフルなプログラミング言語である。 しかし、他の強力なツール同様このパワーがとんでもない騒動を 引き起こすこともある。

無限ループを作る能力があるところがありふれたわざわいを引き起こす。 例えば、つぎのような面白みのないように見えるコードをみてみよう。

'foo' =~ m{ ( o? )* }x;

o? は 'foo' の始まりに マッチし得る。しかし、文字列中の位置はこの マッチでは移動し得ない。 o? は何度も * でマッチする。 もう一つのありがちな似たような循環の作り方は //g を使うことである。

@matches = ( 'foo' =~ m{ o? }xg );

さもなければ

print "match: <$&>\n" while 'foo' =~ m{ o? }xg;

あるいは split() によるループなどがある。

しかし長い間の経験が多くのプログラミングで 繰り返しを含むコードの利用が仕事を劇的に簡潔にさせることを 教えている。 例えば、次の簡単な例をみてみよう。

@chars = split //, $string;           # // is not magic in split
($whitewashed = $string) =~ s/()/ /g; # parens avoid magic s// /

このように Perl は /()/ という 構文を許す。 これは無限ループを強制的に打ち切ることが出来る。 このルールはどん欲な *+{} などが起こすループとは違った原理に基づいている。 なおここで高レベルのループと言うのは /gsplit() によるループのことを言っている。 (訳注 : この辺は意訳)

低レベルのループは長さゼロの文字列にマッチした表現の繰り返しを 検知した時に中断される。

m{ (?: NON_ZERO_LENGTH | ZERO_LENGTH )* }x;

は次と等価になる。

m{   (?: NON_ZERO_LENGTH )*
   |
     (?: ZERO_LENGTH )?
}x;

高レベルのループは繰り返しの間に直前のマッチの 長さがゼロかどうかをチェックするコードをいれる。 ループを中断するには 長さゼロのマッチの後のマッチが長さゼロになることを禁じればいい。 この禁止コードはバックトラッキングにも干渉する。 (バックトラッキングのセクションを参考のこと) そして、最良のマッチが長さゼロなら 次善のマッチを選択する。

例えば、

$_ = 'bar';
s/\w??/<$&>/g;

は "<<b><><a><><r><>"> となる。 各文字列の位置で、 最良のマッチはどん欲ではない ?? によって与えられる。 そしてそれは長さゼロである。 次善のマッチは \w によるものである。 このように、長さゼロのマッチは 長さ 1 のマッチで置き換えられる。

同様に、繰り返しの m/()/g については次善のマッチは 一きざみ先の位置にマッチするようなマッチである。

追加的な長さゼロのマッチのコードはマッチする文字列に関したものである。 そしておのおの pos() でリセットされる。

カスタム正規表現エンジンを作る

定数のオーバーロード( overload マニュアルページを参考のこと) によって正規表現エンジンの拡張を簡単に行える。

例えば、新しい正規表現のエスケープシーケンス \Y| を作って、それが空白と非空白文字の境界に マッチさせるようにしたいとする。 (?=\S)(?<!\S)|(?!\S)(?<=\S) というパターンがそういった空白文字の境界に 正確にマッチすることに注意すれば、 この複雑なバージョンのかわりに \Y| を使いたいのである。 このために、customre というモジュールを作ることが出来る。

package customre;
use overload;

sub import {
  shift;
  die "No argument to customre::import allowed" if @_;
  overload::constant 'qr' => \&convert;
}

sub invalid { die "/$_[0]/: invalid escape '\\$_[1]'"}

my %rules = ( '\\' => '\\',
              'Y|' => qr/(?=\S)(?<!\S)|(?!\S)(?<=\S)/ );
sub convert {
  my $re = shift;
  $re =~ s{
            \\ ( \\ | Y . )
           }
           { $rules{$1} or invalid($re,$1) }sgex;
  return $re;
}

これによって use customre は定数正規表現中であたらしいエスケープシーケンスを 使うことが出来る。(つまり、変数展開がない状況でということ)。 overload マニュアルページに書いてあるように、 この変換はリテラルの正規表現中だけでのみ有効である。 例えば、 \Y|$re\Y| などといった変数部分は明示的に変換する必要がある。 (更に、$re の中で \Y| の意味を有効にする必要もある。):

use customre;
$re = <>;
chomp $re;
$re = customre::convert $re;
/\Y|$re\Y|/;

参照

perlop マニュアルページの "Regexp Quote-Like Operators" セクション

perlop マニュアルページの "Gory details of parsing quoetd constructs" セクション

perlfunc マニュアルページの pos 関数のエントリ

perllocale マニュアルページ

Jeffrey Friedl 著 "Mastering Regular Expressions" (邦訳: 『詳説 正規表現』オライリー・ジャパン)

(訳注 : perl のマニュアルページ関係は perl の配布元の サイトなどにアクセスすることで見ることが出来ます。 また、Linux や FreeBSD をインストールしてある場合には man コマンドで見れます。)

$Id: perlre.html,v 1.4 2000/05/10 14:27:34 ageha Exp $