Regex lookahead, lookbehind e grupos atômicos

314

Encontrei essas coisas no meu corpo regex, mas não tenho idéia do que posso usá-las. Alguém tem exemplos para que eu possa tentar entender como eles funcionam?

(?!) - negative lookahead
(?=) - positive lookahead
(?<=) - positive lookbehind
(?<!) - negative lookbehind

(?>) - atomic group
Spidfire
fonte
18
Por que o site regex não possui uma tabela simples como essa? Em vez disso, eles têm blocos de texto explicando apenas. regular-expressions.info/lookaround.html
WhiteCat
3
@Whitecat Tente: regex101.com regexr.com
Andrew

Respostas:

852

Exemplos

Dada a sequência foobarbarfoo:

bar(?=bar)     finds the 1st bar ("bar" which has "bar" after it)
bar(?!bar)     finds the 2nd bar ("bar" which does not have "bar" after it)
(?<=foo)bar    finds the 1st bar ("bar" which has "foo" before it)
(?<!foo)bar    finds the 2nd bar ("bar" which does not have "foo" before it)

Você também pode combiná-los:

(?<=foo)bar(?=bar)    finds the 1st bar ("bar" with "foo" before it and "bar" after it)

Definições

Olhe adiante positivo (?=)

Encontre a expressão A em que a expressão B segue:

A(?=B)

Olhe para o lado negativo (?!)

Encontre a expressão A em que a expressão B não segue:

A(?!B)

Olhe para trás positivo (?<=)

Encontre a expressão A em que a expressão B precede:

(?<=B)A

Olhe para trás negativo (?<!)

Encontre a expressão A em que a expressão B não precede:

(?<!B)A

Grupos atômicos (?>)

Um grupo atômico sai de um grupo e joga fora padrões alternativos após o primeiro padrão correspondente dentro do grupo (o retorno é desativado).

  • (?>foo|foot)saplicado a footscorresponderá à sua primeira alternativa foo, falhará como snão segue imediatamente e parar quando o retorno estiver desativado

Um grupo não atômico permitirá retroceder; se a correspondência subsequente falhar, ela retornará e usará padrões alternativos até que uma correspondência para toda a expressão seja encontrada ou todas as possibilidades sejam esgotadas.

  • (foo|foot)saplicado à footsvontade:

    1. corresponda à sua primeira alternativa foo, falhe como snão segue imediatamente footse retorne à sua segunda alternativa;
    2. combine com a segunda alternativa e foot, em seguida, obtenha o sucesso simediatamente a seguir footse pare.

Alguns recursos

Testadores online

skyfoot
fonte
1
O que você quer dizer com parte "encontra a segunda barra"? Existe apenas uma barra na expressão / sequência. Graças
Ziggy
2
@ ziggy a string que está sendo testada é "foobarbarfoo". Como você pode ver, há dois foo e duas barras na corda.
skyfoot
4
Alguém pode explicar quando alguém pode precisar de um grupo atômico? Se eu só preciso combinar com a primeira alternativa, por que eu gostaria de dar várias alternativas?
arviman
2
Melhor explicação sobre o grupo atômica em esta resposta . Alguém pode editar aqui para completar esta resposta didática?
27618 Peter Krauss
5
Apenas uma observação de que essa resposta era essencial quando eu acabei em um projeto que exigia costeletas graves de regex. Esta é uma explicação concisa excelente e detalhada.
Tom Coughlin
215

Lookarounds são asserções de largura zero. Eles verificam uma regex (à direita ou à esquerda da posição atual - com base na frente ou atrás), obtém êxito ou falha quando uma correspondência é encontrada (com base na positiva ou negativa) e descarta a parte correspondente. Eles não consomem nenhum caractere - a correspondência para a regex que os segue (se houver) começará na mesma posição do cursor.

Leia regular-expression.info para mais detalhes.

  • Lookahead positivo:

Sintaxe:

(?=REGEX_1)REGEX_2

Corresponder apenas se REGEX_1 corresponder; depois de corresponder a REGEX_1, a correspondência é descartada e a pesquisa por REGEX_2 começa na mesma posição.

exemplo:

(?=[a-z0-9]{4}$)[a-z]{1,2}[0-9]{2,3}

REGEX_1 [a-z0-9]{4}$corresponde a quatro caracteres alfanuméricos seguidos pelo final da linha.
REGEX_2 é o [a-z]{1,2}[0-9]{2,3}que corresponde a uma ou duas letras seguidas por dois ou três dígitos.

REGEX_1 garante que o comprimento da string seja realmente 4, mas não consome nenhum caractere, para que a pesquisa por REGEX_2 comece no mesmo local. Agora REGEX_2 garante que a sequência corresponda a outras regras. Sem olhar para frente, seria igual a três ou cinco cordas.

  • Lookahead negativo

Sintaxe:

(?!REGEX_1)REGEX_2

Corresponder apenas se REGEX_1 não corresponder; depois de verificar REGEX_1, a pesquisa por REGEX_2 começa na mesma posição.

exemplo:

(?!.*\bFWORD\b)\w{10,30}$

A parte antecipada verifica FWORDa sequência e falha se a encontrar. Se não encontrar FWORD, o olhar adiante terá êxito e a parte a seguir verificará se o comprimento da string está entre 10 e 30 e se contém apenas caracteres de palavrasa-zA-Z0-9_

O look-behind é semelhante ao look-ahead: apenas olha atrás da posição atual do cursor. Alguns tipos de expressões regulares como o javascript não suportam asserções de look-behind. E a maioria dos sabores que o suportam (PHP, Python etc) exigem que essa parte do look-behind tenha um comprimento fixo.

  • Os grupos atômicos basicamente descartam / esquecem os tokens subseqüentes no grupo quando um token corresponde. Verifique esta página para exemplos de grupos atômicos
Amarghosh
fonte
seguindo sua explicação, parece não funcionar em javascript, /(?=source)hello/.exec("source...hummhellosource ") = null. Sua explicação está correta?
Helin Wang
@HelinWang Essa explicação está correta. Seu regex espera uma string que seja ao mesmo tempo fonte e olá!
Amarghosh
@jddxf Gostaria de elaborar?
Amarghosh 04/10
@Amarghosh Concordo com "Eles verificam um regex (à direita ou à esquerda da posição atual - com base na frente ou atrás), obtém êxito ou falha quando uma correspondência é encontrada (com base na positiva ou negativa) e descarta a correspondência parte.". Então lookahead deve verificar se há um regex para a direita da posição atual ea sintaxe de antecipação positiva deve ser x (= y?)
jddxf
@Amarghosh (?=REGEX_1)REGEX_2só corresponderia se REGEX_2vier depois REGEX_1 ?
aandis
0

Grokking olha rapidamente.
Como distinguir lookahead e lookbehind? Faça um passeio de 2 minutos comigo:

(?=) - positive lookahead
(?<=) - positive lookbehind

Suponha

    A  B  C #in a line

Agora, perguntamos a B: onde você está?
B tem duas soluções para declarar sua localização:

Um, B tem A à frente e tem C bebind
Dois, B está à frente (à frente) de C e atrás (a atrás) A.

Como podemos ver, o passado e o futuro são opostos nas duas soluções.
Regex é a solução dois.

Cálculo
fonte