サブパターン

サブパターンは、丸カッコで括られたパターンのことで、ネストも可能です。 パターンの一部をサブパターンにすると、以下の 2 つのことが可能になります。

  1. 選択肢の範囲の指定 (localize)。例えば、パターン cat(aract|erpillar|) は、単語 "cat", "cataract", "caterpillar" にマッチします。 カッコをつけないと、このパターンは、"cataract", "erpillar" または空の文字列にマッチしてしまいます。

  2. サブパターンによる値の取得(キャプチャ)。 パターン全体としてマッチに成功した場合、対象文字列の内、 サブパターンにマッチした部分の値がコールした側に (pcre_exec() の引数 ovector で) 返されます。 開きカッコの数が(1 から始まって)左から右に数えられ、 キャプチャ用サブパターン (capturing subpattern) の番号が指定されます。

例えば、文字列 "the red king" に対し、パターン

      the ((red|white) (king|queen))
      
をマッチングさせた場合、キャプチャされる部分文字列は、 "red king", "red", "king" であり、 それぞれ 1 番, 2 番, 3 番と番号がふられます。

カッコに 2 つの機能があるということが、いつも良い方に働くわけでは ありません。値をキャプチャする必要はないが、グループ分けのために サブパターンを複数用いたい場合も少なくありません。開きカッコの後に "?:" を付けると、そのサブパターンは値のキャプチャを行わず、 キャプチャ用サブパターンの番号としてもカウントされません。例えば、 文字列 "the white queen" に対し、次のパターンをマッチングさせてみましょう。

      the ((?:red|white) (king|queen))
      
キャプチャされる部分文字列は、"white queen" と "queen" であり、 それぞれ 1 番と 2 番に番号付けされます。キャプチャ可能な部分文字列の 数は最大で 65535 までです。 そんな大量のパターンをコンパイルするのはそもそも無理かもしれませんが、 そのあたりは libpcre の configure 時のオプションしだいです。

簡略形として、値のキャプチャをしないサブパターンの先頭で オプションの設定をする場合、オプションの文字を "?" と ":" の間に入れることができます。つまり、次の 2 つのパターン、

(?i:saturday|sunday)
(?:(?i)saturday|sunday)

は、まったく同じ文字列集合にマッチします。 選択肢は左から右に試行され、オプションはサブパターンの終端に達するまで リセットされないので、ある選択枝にあるオプション設定は後に続く 選択枝にも作用します。このため、上のパターンは、"Saturday" と同様に "SUNDAY" にもマッチします

(?P<name>pattern) という記法を用いて サブパターンに名前をつけることができます。 このサブパターンにマッチした部分は、マッチ時に返される配列内で 通常どおりの数値添字によるアクセスだけでなく名前でもアクセスできるようになります。 PHP 5.2.2 からは、二通りの別の構文 (?<name>pattern) および (?'name'pattern) も用意されています。

複数の条件にマッチさせたいときに、 ひとつの正規表現の中でサブグループを切り替えなければならないこともあります。 通常は、たとえその中のいずれかひとつにしかマッチしなかったとしても それぞれに個別の後方参照番号が振られます。 これを解決するために使えるのが (?| 構文で、 重複した番号を振ることができるようになります。 次の正規表現で文字列 Sunday をマッチングするとどうなるでしょうか。

(?:(Sat)ur|(Sun))day

Sun が後方参照 2 に格納され、 後方参照 1 は空となります。Sat にマッチした場合は後方参照 1 に入り、後方参照 2 は存在しません。 この問題を解決するには、パターンを変更して (?| を使うようにします。

(?|(Sat)ur|(Sun))day

このパターンを使えば、SunSat の両方が後方参照 1 に格納されます。

add a note add a note

User Contributed Notes 1 note

up
2
mike at eastghost dot com
2 years ago
(?:(?!string).)

?: makes a subpattern

?! is a negative look-ahead.

Putting negative look-ahead before the dot causes regex engine to first find any occurrence of the negative look-ahead string, and only then, if the negative look-ahead string is not present, should an arbitrary character (due to the dot) match.
To Top