У меня возникают трудности с пониманием того, как \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 />'; } ?>
Это прямо из документов
Четвертое использование обратной косой черты для некоторых простых утверждений. Утверждение определяет условие, которое должно выполняться в определенной точке совпадения, без использования каких-либо символов из строки темы. Ниже описывается использование подшаблонов для более сложных утверждений. Утверждения с обратной косой чертой
\G first matching position in subject
Утверждение \ G истинно только тогда, когда текущая позиция соответствия находится в начальной точке совпадения, как указано аргументом offset preg_match (). Он отличается от \ A, когда значение смещения отличное от нуля.
http://www.php.net/manual/en/regexp.reference.escape.php
Вам придется немного прокручивать эту страницу, но она есть.
В рубине есть действительно хороший пример, но в php он одинаковый.
Как работает Anchor \ z и \ G в Ruby?
\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~
Строка состоит из сочетания:
\
и '
, и пробелы сохраняются. Пустую строку можно указать с помощью строки с одиночным кавычкой. \
или '
. Для простоты предположим, что вход не содержит новой строки (в реальном случае вам нужно ее рассмотреть). Это добавит сложности регулярного выражения, не продемонстрировав этого.
Регулярное выражение RAW для строки с одиночными кавычками равно '(?:[^\\']|\\[\\'])*+'
И регулярное выражение RAW для строки без кавычек – [^\s'\\]++
Однако вам не нужно слишком много заботиться о двух частях регулярного выражения выше.
В приведенном ниже решении с \G
можно убедиться, что, когда двигатель не находит никакого совпадения, все символы от начала строки до позиции последнего совпадения были уничтожены. Поскольку он не может пропускать символ, двигатель перестанет соответствовать, если ему не удастся найти правильное соответствие для обеих спецификаций токенов, вместо того, чтобы захватывать случайные вещи в остальной части строки.
строительство
На первом этапе построения мы можем собрать это регулярное выражение:
\G(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
Или просто поставить (это не регулярное выражение – просто чтобы было легче читать):
\G(Singly_quote_regex|Unquoted_regex)
Это будет соответствовать только первому токену, поскольку, когда он пытается выполнить сопоставление во второй раз, совпадение останавливается в пространстве перед 'some input...
.
Нам просто нужно добавить бит, чтобы можно было использовать 0 или более пробелов, так что в последующем матче расходуется пространство в позиции, оставленной последним совпадением:
\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
Регулярное выражение теперь правильно идентифицирует маркеры, как видно здесь .
Регулярное выражение может быть дополнительно модифицировано так, чтобы оно возвращало остальную часть строки, когда движок не смог получить действительный токен:
\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++)|((?s).+$))
Поскольку чередование выполняется в порядке слева направо, последний вариант ((?s).+$)
Будет соответствовать тогда и только тогда, когда строка впереди не будет содержать действительный одиночный кавычек или некорректный токен. Это можно использовать для проверки на наличие ошибок.
Первая группа захвата будет содержать текст внутри строки с одним кавычком, для чего требуется дополнительная обработка, чтобы превратить ее в желаемый текст (здесь это не очень важно, поэтому я оставляю это как упражнение для читателей). Вторая группа захвата будет содержать строку без кавычек. Третья группа захвата действует как индикатор того, что входная строка недействительна.
Демо для окончательного регулярного выражения
Вывод
Вышеприведенный пример демонстрирует один сценарий использования \G
в токенизации. Могут быть другие способы использования, с которыми я не сталкивался.