Подтвердить что ты не робот

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

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

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

Я разберусь с тем, что, как я думаю, понял:

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Ссылки


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

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

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

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

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, так как оно не поддерживает lookbehind. Тем не менее, он поддерживает lookahead, поэтому мы можем сделать что-то подобное с #([a-z]+)(?=#), которое соответствует (как видно на rubular.com):

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

Ссылки

Ответ 2

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

(?<=#)    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 и lookbehind очень полезны во многих случаях. Рассмотрим, например, правило "соответствовать всем b, за которым не следует a". Ваша первая попытка может быть чем-то вроде b[^a], но это не так: это также будет соответствовать bu в bus или bo в boy, но вам нужно только b. И он не будет соответствовать b в cab, хотя это не сопровождается a, потому что больше символов не должно совпадать.

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