Я имею следующий regex в программе 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>
используется для именования групп, но в этом случае угловая скобка никогда не закрывается.
Я не мог найти ?=
в документах и поиске это действительно трудно, потому что поисковые системы главным образом проигнорируют те специальные символы.
Они называются поисковыми запросами; они позволяют вам утверждать, совпадает ли шаблон или нет, без фактического совпадения. Существует 4 основных метода поиска:
...
(? = Шаблон)
- ... вправо от текущей позиции (смотрите вперед ) (? <= Шаблон)
- ... слева от текущей позиции (посмотрите за )
(?! шаблон)
- ... вправо (? - ... влево
В качестве простого напоминания для поиска:
=
является положительным , !
отрицательный <
выглядит позади , в противном случае он выглядит впереди Кто-то может возразить, что поисковые запросы в приведенном выше шаблоне не нужны, и # ([^ #] +) #
отлично справится с этой задачей (извлечение строки, захваченной \ 1
, чтобы получить не- #
).
Не совсем. Разница в том, что, поскольку поиск не соответствует #
, его можно «использовать» снова при следующей попытке найти совпадение.Упрощенно говоря, поисковые запросы позволяют «совпадениям» перекрываться.
Рассмотрим следующую входную строку:
and #one# and #two# and #three#four#
Теперь # ([az] +) #
даст следующие совпадения (, как показано на rubular.com ):
and #one# and #two# and #three#four#
\___/ \___/ \_____/
Сравните это с (? <= #) [Az] + (? = #)
, которое соответствует:
and #one# and #two# and #three#four#
\_/ \_/ \___/ \__/
К сожалению, это нельзя продемонстрировать на rubular.com, поскольку он не поддерживает смотреть за. Однако он поддерживает предварительный просмотр, поэтому мы можем сделать что-то подобное с # ([az] +) (? = #)
, которое соответствует (, как показано на rubular.com ):
and #one# and #two# and #three#four#
\__/ \__/ \____/\___/
Как упомянул другой постер, это 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
Таким образом, это будет соответствовать всем символам между двумя #
s.
Lookaheads и lookbehinds очень полезны во многих случаях. Рассмотрим, например, правило "Искать все b
s, за которыми не следует 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