Как работает регулярное выражение '(?<=#)[^#]+(?=#)'?

У меня есть следующее регулярное выражение в программе на C#, и мне трудно понять это:

(?<=#)[^#]+(?=#)

Я разобью это до того, что, я думаю, я понял:

(?<=#)    a group, matching a hash. what's `?<=`?
[^#]+     one or more non-hashes (used to achieve non-greediness)
(?=#)     another group, matching a hash. what's the `?=`?

Так что проблема у меня заключается в ?<= а также ?< часть. Из чтения MSDN, ?<name> используется для именования групп, но в этом случае угловая скобка никогда не закрывается.

Я не смог найти ?= в документах, и поиск его действительно сложен, потому что поисковые системы будут в основном игнорировать эти специальные символы.

3 ответа

Решение

Они называются двойниками; они позволяют вам утверждать, соответствует шаблон или нет, без фактического соответствия. Есть 4 основных подхода:

  • Положительные отзывы: посмотрим, сможем ли мы соответствовать pattern...
    • (?=pattern) - ... справа от текущей позиции (смотреть в будущее)
    • (?<=pattern) - ... слева от текущей позиции (смотреть сзади)
  • Отрицательные взгляды - посмотрим, сможем ли мы НЕ соответствовать pattern
    • (?!pattern) - ... направо
    • (?<!pattern) - ... налево

В качестве легкого напоминания, для обхода:

  • = положительно, ! отрицательно
  • < это смотреть сзади, иначе это смотреть вперед

Рекомендации


Но зачем использовать обходные пути?

Можно утверждать, что обходные пути в приведенной выше схеме не нужны, и #([^#]+)# будет делать работу очень хорошо (извлечение строки, захваченной \1 чтобы получить не#).

Не совсем. Разница в том, что, поскольку внешний вид не соответствует #, он может быть снова "использован" при следующей попытке найти совпадение. Проще говоря, обходные пути позволяют перекрывать "совпадения".

Рассмотрим следующую входную строку:

and #one# and #two# and #three#four#

Сейчас, #([a-z]+)# даст следующие совпадения ( как видно на rubular.com):

and #one# and #two# and #three#four#
    \___/     \___/     \_____/

Сравните это с (?<=#)[a-z]+(?=#), который соответствует:

and #one# and #two# and #three#four#
     \_/       \_/       \___/ \__/

К сожалению, это не может быть продемонстрировано на rubular.com, так как он не поддерживает просмотр назад. Тем не менее, он поддерживает lookahead, поэтому мы можем сделать что-то подобное с #([a-z]+)(?=#), что соответствует ( как видно на rubular.com):

and #one# and #two# and #three#four#
    \__/      \__/      \____/\___/

Рекомендации

Как упоминалось в другом плакате, это обходные пути, специальные конструкции для изменения того, что соответствует и когда. Это говорит:

(?<=#)    match but don't capture, the string `#`
            when followed by the next expression

[^#]+     one or more characters that are not `#`, and

(?=#)     match but don't capture, the string `#`
            when preceded by the last expression

Так что это будет соответствовать всем персонажам между двумя #s.

Lookaheads и lookbehinds очень полезны во многих случаях. Рассмотрим, например, правило "соответствовать всем". bне сопровождается a"Ваша первая попытка может быть чем-то вроде b[^a], но это не правильно: это также будет соответствовать bu в bus или bo в boy, но вы хотели только b, И это не будет соответствовать b в cab, хотя это не сопровождается a, потому что больше нет символов для сопоставления.

Чтобы сделать это правильно, вам нужно посмотреть в будущее: b(?!a), Это говорит "соответствуй b но не соответствует a впоследствии, и не делайте эту часть матча ". Таким образом, он будет соответствовать только b в boloчего ты хочешь; аналогично это будет соответствовать b в cab,

Они называются осмотрами: http://www.regular-expressions.info/lookaround.html

Другие вопросы по тегам