\G
正規表現の PHP フレーバーでアンカーがどのように機能するかを理解するのに苦労しています。
同じ文字列の複数の一致が行われている状況\G
ではなく、(間違っているかもしれませんが) 使用されると考える傾向があります。^
誰かがどのよう\G
に使用すべきかの例を示し、それがどのように、そしてなぜ機能するかを説明してもらえますか?
アップデート
\Gは、一致の連続チェーンの一部である一致のみを返すようにパターンを強制します。最初の一致から、後続の各一致の前に一致が必要です。チェーンを壊すと、試合は終了します。
<?php
$pattern = '#(match),#';
$subject = "match,match,match,match,not-match,match";
preg_match_all( $pattern, $subject, $matches );
//Will output match 5 times because it skips over not-match
foreach ( $matches[1] as $match ) {
echo $match . '<br />';
}
echo '<br />';
$pattern = '#(\Gmatch),#';
$subject = "match,match,match,match,not-match,match";
preg_match_all( $pattern, $subject, $matches );
//Will only output match 4 times because at not-match the chain is broken
foreach ( $matches[1] as $match ) {
echo $match . '<br />';
}
?>
これはドキュメントから直接です
バックスラッシュの 4 番目の用途は、特定の単純なアサーションです。アサーションは、対象文字列の文字を消費することなく、一致の特定の時点で満たす必要がある条件を指定します。より複雑なアサーションのサブパターンの使用については、以下で説明します。バックスラッシュされたアサーションは
\G
first matching position in subject
\G アサーションは、preg_match() のオフセット引数で指定されているように、現在の一致位置が一致の開始点にある場合にのみ真です。オフセットの値がゼロ以外の場合、\A とは異なります。
http://www.php.net/manual/en/regexp.reference.escape.php
そのページを少し下にスクロールする必要がありますが、そこにあります。
ruby には本当に良い例がありますが、php でも同じです。
\G
これは、文字列の先頭、または最後の一致の最後の文字が消費されるポイントのいずれかです。
トークンが有効であることを確認しながら、複雑なトークン化を行う必要がある場合に特に便利です。
問題例
この入力をトークン化する例を見てみましょう。
input 'some input in quote' more input '\'escaped quote\'' lots@_$of_fun ' \' \\ ' crazy'stuff'
これらのトークンに (私~
は文字列の終わりを示すために使用します):
input~
some input in quote~
more~
input~
'escaped quote'~
lots@_$of_fun~
' \ ~
crazy~
stuff~
文字列は次の組み合わせで構成されます。
\
およびのエスケープを可能にする単一引用符付きの文字列、'
およびスペースは保持されます。空の文字列は、単一引用符で囲まれた文字列を使用して指定できます。\
orは含まれません'
。簡単にするために、入力に改行が含まれていないと仮定します (実際には、それを考慮する必要があります)。ポイントを示すことなく、正規表現の複雑さが増します。
単一引用符で囲まれた文字列'(?:[^\\']|\\[\\'])*+'
の RAW 正規表現は であり、引用符で囲まれていない文字列の RAW 正規表現は[^\s'\\]++
ですが、上記の 2 つの正規表現についてあまり気にする必要はありません。
以下のソリューションで\G
は、エンジンが一致を見つけられなかった場合に、文字列の先頭から最後の一致の位置までのすべての文字が消費されていることを確認できます。文字をスキップできないため、トークンの両方の仕様に対して有効な一致が見つからない場合、エンジンは文字列の残りの部分をランダムに取得するのではなく、一致を停止します。
工事
構築の最初のステップで、次の正規表現をまとめることができます。
\G(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
または簡単に言えば (これは正規表現ではありません- 読みやすくするためです):
\G(Singly_quote_regex|Unquoted_regex)
これは最初のトークンのみに一致します。2 回目の一致を試みると、一致は の前のスペースで停止するため'some input...
です。
0 以上のスペースを許可するためにビットを追加する必要があるだけです。これにより、後続の一致で、最後の一致によって残された位置のスペースが消費されます。
\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
ここで見られるように、上記の正規表現はトークンを正しく識別するようになりました。
エンジンが有効なトークンを取得できなかった場合に残りの文字列を返すように、正規表現をさらに変更できます。
\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++)|((?s).+$))
代替は左から右の順に試行されるため、((?s).+$)
前の文字列が有効な一重引用符または非引用符を構成しない場合にのみ、最後の代替が一致します。これは、エラーのチェックに使用できます。
最初のキャプチャ グループには、一重引用符で囲まれた文字列内のテキストが含まれます。これは、目的のテキストに変換するために追加の処理が必要です (ここではあまり関係がないため、読者への演習として残します)。2 番目のキャプチャ グループには、引用符で囲まれていない文字列が含まれます。そして、3 番目のキャプチャ グループは、入力文字列が無効であることを示すインジケーターとして機能します。
結論
上記の例は\G
、トークン化で を使用する 1 つのシナリオを示しています。私が出会ったことのない他の用途があるかもしれません。