3

問題

PHP はPCRE正規表現ライブラリを使用しますが、これは後読みでの繰り返しをサポートしていません。

繰り返しが後読み (例: (?<=\d+)) にある場合、PHP は通常、次のような警告を発行します。

警告: preg_match_all(): コンパイルに失敗しました: 10 行目の lookbehind.php のオフセット 7 で、後読みアサーションが固定長ではありません

しかし、コンパイルが失敗するはずなのに失敗しないケースを発見しました。

予想どおり、これらはコンパイルに失敗します。

  • /(?<=X*)a/
  • /(?<=X+)a/
  • /(?<=(X)*)a/

ただし、/(?<=(X)+)a/コンパイルします。/(?<=(X){1,})a/これは、同様にコンパイルされる と機能的に同等である必要があります。一方、実際にその範囲に上限を追加すると
(例: /(?<=(X){1,2})a/)、コンパイルに失敗します。私もコンパイルに失敗するはずだ/(?<=(X)+)a/と思いますが、そうではありません。/(?<=(X){1,})a/なぜだめですか?

実験

ここにいくつかのコードがあります:

$str = 'aXaaXXaaaXXXaaaa';

$regex = '/(?<=((?:X)+))a+/';

preg_match_all($regex, $str, $matches, PREG_OFFSET_CAPTURE|PREG_SET_ORDER);
print_r($matches);

複数の の周りにキャプチャ グループを追加するために、パターンを少し複雑にしましたX。ここに私の結果があります:

Array (
    [0] => Array (
            [0] => Array (
                    [0] => aa
                    [1] => 2
                )
            [1] => Array (
                    [0] => X
                    [1] => 1
                )
        )
    [1] => Array (
            [0] => Array (
                    [0] => aaa
                    [1] => 6
                )
            [1] => Array (
                    [0] => X
                    [1] => 5
                )
        )
    [2] => Array (
            [0] => Array (
                    [0] => aaaa
                    [1] => 12
                )
            [1] => Array (
                    [0] => X
                    [1] => 11
                )
        )
)

as に続くsと明確に一致しXます。これは正しいです。Xただし、サブパターン 1は、すべてではなく1 つのみに一致するように見えます。a後読みの先頭にan を追加してX、間にあるすべての s を検出する必要がある場合、結果は次のようになります。

$regex = '/(?<=(a(?:X)+))a+/';
Array (
    [0] => Array (
            [0] => Array (
                    [0] => aa
                    [1] => 2
                )
            [1] => Array (
                    [0] => aX
                    [1] => 0
                )
        )
)

1 回だけ一致します ( が 1 つしかない場合X)。事実上、(X)+(X){1,}縮小されて(X){1}います (これは固定長のため許容されます)。

結論

「バグ!」と泣くのは嫌いです。期待どおりに動作しないものを見つけたらすぐに、しかしそれは確かにそのように思えます。パターンは期待どおりに拒否されず、有効なパターンであっても期待どおりに動作しません。

だから私は尋ねます:

  • このように動作する正当な理由はありますか?
  • これが に当てはまるのに に当てはまらないのはなぜ+ですか*?
  • 括弧が重要な理由: X+失敗します。(X)+許可されています ?

どんな洞察も大歓迎です。ありがとうございました。

4

2 に答える 2

1

これは PHP のバグではありません。それがバグである場合 (そしてバグのように見える場合)、それは PCRE バグであり、そこで報告する必要があります。ただし、PCRE のバージョンを確認phpinfo()して、最新バージョンと比較してください。最新でない場合は、バグ レポートを投稿する前に、最新の PCRE で同じ正規表現を直接実行してみてください。

于 2012-08-23T05:41:51.343 に答える
1

PCRE バージョン 8.32-RC1 2012-08-08

re> /(?<=(X)+)a/ 失敗: 後読みアサーションがオフセット 8 で固定長ではありません re>

おそらくバグでした。最新の PCRE に更新してください。

ところで、\K を使用して無制限の後方参照を作成できます。

于 2012-08-24T14:22:22.530 に答える