Как работает регулярное выражение '(? <= #) [^ #] + (? = #)'? - PullRequest
20 голосов
/ 22 июня 2010

У меня есть следующее регулярное выражение в программе на 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 ]

33 голосов
/ 22 июня 2010

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

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

Как простое напоминание, для поиска:

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

Ссылки


Но зачем использовать lookarounds?

Можно утверждать, что обходные пути в приведенном выше шаблоне не нужны, и #([^#]+)# прекрасно справится с задачей (извлекая строку, захваченную \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, так как он не поддерживает просмотр назад. Тем не менее, он поддерживает прогнозирование, поэтому мы можем сделать что-то похожее с #([a-z]+)(?=#), что соответствует ( как видно на rubular.com ):

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

Ссылки

4 голосов
/ 22 июня 2010

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

(?<=#)    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

Так что это будет соответствовать всем символам между двумя # с.

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

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

1 голос
/ 22 июня 2010

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

...