言明

言明 (assertion) とは、カレントのマッチング位置の直前・直後の文字に対する テストであり、文字を消費 (consume)〔つまり文字自体にマッチ〕しません。 単純な言明コード \b, \B, \A, \Z, \z, ^ および $ については、 エスケープシーケンス で説明しました。より複雑な言明は、サブパターンを用いて記述します 〔言明サブパターン (assertion subpattern) と呼ばれる〕。 言明サブパターンには、2 種類あります。対象文字列において カレントの位置の先を読むものと、後ろを読むものです。

言明サブパターンは、カレントのマッチング位置を変更しないことを除き、 通常と同じようにマッチングが行われます。先読み言明 (lookahead assertion) は、 肯定の言明 (positive assertion) の場合 (?= で始まり、 否定の言明 (negative assertion) の場合 (?! で始まります。例えば、

      \w+(?=;)
      
は、セミコロンが後に続く単語にマッチしますが、 マッチ対象それ自体にはセミコロンは含まれません。また、
      foo(?!bar)
      
は、"bar" が後ろに続かない "foo" にマッチします。 なお、一見、良く似たパターンですが
      (?!foo)bar
      
は、"foo" 以外のものの後にある "bar" を見つけるものではないことに 注意してください。これは、どこにある "bar" とでもマッチしてしまいます。 続く 3 文字が "bar" である場合、 (?!foo) は常に真となってしまうからです。 このような探索を実現するためには、戻り読み言明 (lookbehind assertion) が必要です。

戻り読み言明は、肯定の言明の場合 (?<= で始まり、 否定の言明の場合 (?<! で始まります。例えば、

      (?<!foo)bar
      
は、"foo" 以外の後にある "bar" の存在を見つけるものです。 戻り読み言明内のパターンは、それがマッチし得る文字列の長さが 固定でなければなりません〔繰り返しを指定できません〕。ただし、 選択肢を用いた場合、各選択肢は〔固定長でなければいけませんが〕 すべて同じ長さである必要はありません。つまり、
      (?<=bullock|donkey)
      
とはできますが、
      (?<!dogs?|cats?)
      
は、コンパイル時にエラーになります。 戻り読み言明の最上位においてのみ、異なる長さの文字列にマッチするような 選択肢が使用可能です。Perl 5.005 においては、すべての選択肢が 同じ長さの文字列にマッチする必要があります。つまり、この機能は PCRE の拡張機能です。
      (?<=ab(c|de))
      
という戻り読み言明は、最上位にひとつの選択肢しかなく、 その選択肢は異なる長さの文字列にマッチしうるので、不正です。 しかし、
      (?<=abc|abde)
      
のように、最上位において選択肢を 2 つ用いるように 書き換えると使用可能です。

後方言明の実装においては、選択肢ことに一時的に固定の幅だけ カレントの位置を後退させ、マッチを試みます。カレントの位置の前に 十分な文字がない場合は、マッチは失敗とみなされます。 再試行無しのサブパターンと組み合わせた戻り読み言明は、 文字列の終端でのマッチングに特に有用です。 再試行無しのサブパターンについてのセクションの最後にて例を示します。

(任意の種類の)複数の言明を連続して指定することも可能です。例えば、

      (?<=\d{3})(?<!999)foo
      
は、"999" でない 3 桁の数字の後にある "foo" にマッチします。 それぞれの言明は、対象文字列の同じ場所に独立して適用されることに 注意して下さい。まず、前の 3 文字がすべて数字であることがチェックされ、 続いて、同じ 3 文字が "999" でないことが確認されます。このパターンは、 "foo" の前に 6 個の文字があり、その前半が数字で後半の 3 文字が "999" でないというパターンにマッチするものではありません。例えば、"123abcfoo" にはマッチしません。これを行うパターンは次のようになります。
      (?<=\d{3}...)(?<!999)foo
      

この時、最初の言明は、先行する 6 つの文字を探し、 最初の 3 文字が数字であることを確認します。続いて、2 番目の言明は、 先行する 3 文字が "999" でないことを確認します。

言明は、自由に組み合わせてネスト可能です。例えば、

      (?<=(?<!foo)bar)baz
      
は、"foo" 以外の後にある "bar" の後に有る "bar" があればマッチします。 一方、
      (?<=\d{3}...(?<!999))foo
      
は、999 でない 3 桁の数字とさらに 3 文字の後に続く "foo" にマッチするパターンです。

言明サブパターンは、キャプチャ用サブパターンではありません 〔値のキャプチャは行われません〕。繰り返しもできません。 同じことを複数回言明しても意味がないからです。 キャプチャ用サブパターンが言明の内部に含まれている場合、 言明の種類に関係なく、キャプチャ用サブパターンの番号付けにあたって カウントされます。しかし、文字列のキャプチャは、肯定の言明に対してのみ 行われます。否定の言明の中で行っても無意味だからです。

カッコ付サブパターンによる言明は、最大 200 まで用いることができます。

add a note add a note

User Contributed Notes 1 note

up
-23
daevid at daevid dot com
4 years ago
removes // comments but NOT the stuff after http://

$sBlob = preg_replace("@\s*(?<!:)//.*?$@m",'',$sBlob);

Although, as Sean Greenslade pointed out, it will fail in this EDGE case since the comments are within quotes, but who does that anyways?

"Lol slashes // are // fun";
To Top