Existe uma maneira de obter o equivalente a um lookbehind negativo em expressões regulares javascript? Preciso combinar uma sequência que não comece com um conjunto específico de caracteres.
Parece que não consigo encontrar um regex que faça isso sem falhar se a parte correspondente for encontrada no início da string. Lookbehinds negativos parecem ser a única resposta, mas o javascript não tem uma.
EDIT: Este é o regex que eu gostaria de trabalhar, mas não:
(?<!([abcdefg]))m
Portanto, ele corresponderia ao 'm' em 'jim' ou 'm', mas não ao 'jam'
javascript
regex
negative-lookbehind
Andrew Ensley
fonte
fonte
(?:[^abcdefg]|^)(m)
? Como"mango".match(/(?:[^abcdefg]|^)(m)/)[1]
Respostas:
Lookbehind Assertions foi aceito na especificação ECMAScript em 2018.
Lookbehind positivo do uso:
Lookbehind negativo de uso:
Suporte de plataforma:
fonte
Desde 2018, as Lookbehind Assertions fazem parte da especificação de idioma do ECMAScript .
Resposta pré-2018
Como o Javascript suporta lookahead negativo , uma maneira de fazer isso é:
inverta a sequência de entrada
combinar com uma regex invertida
reverter e reformatar as correspondências
Exemplo 1:
Seguindo a pergunta de @ andrew-ensley:
Saídas:
Exemplo 2:
Após o comentário @neaumusic (corresponde,
max-height
mas nãoline-height
, ao tokenheight
):Saídas:
fonte
max-height
, mas nãoline-height
e eu só quero o jogo para serheight
''(?!\()
irá substituir os apóstrofos no''(''test'''''''test
do outro lado, deixando, assim,(''test'NNNtest
ao invés de(''testNNN'test
.Vamos supor que você queira encontrar tudo que
int
não é precedido porunsigned
:Com suporte para look-behind negativo:
Sem suporte para look-behind negativo:
Basicamente, a idéia é pegar n caracteres anteriores e excluir a correspondência com uma previsão negativa, mas também corresponder aos casos em que não há n caracteres anteriores. (onde n é o comprimento do look-behind).
Então, o regex em questão:
traduziria para:
Pode ser necessário brincar com a captura de grupos para encontrar o ponto exato da sequência que lhe interessa ou você deseja substituir uma parte específica por outra.
fonte
"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]")
retorna"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'"
É bem simples e funciona!A estratégia do Mijoja funciona para o seu caso específico, mas não em geral:
Aqui está um exemplo em que o objetivo é corresponder a um l duplo, mas não se for precedido por "ba". Observe a palavra "balll" - o lookbehind verdadeiro deveria ter suprimido os 2 primeiros ls, mas correspondido ao 2º par. Mas, combinando os 2 primeiros l e ignorando essa correspondência como um falso positivo, o mecanismo regexp continua a partir do final dessa correspondência e ignora todos os caracteres do falso positivo.
fonte
Usar
fonte
newString
sempre será igualstring
. Por que tantos votos positivos?"Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1){ return $1 ? $0 : '[match]'; });
. Deve retornarJi[match] Jam Mo[match][match] [match]
. Mas também observe que, como Jason mencionou abaixo, ele pode falhar em certos casos extremos.Você pode definir um grupo que não captura, negando seu conjunto de caracteres:
... que corresponderia a todos os
m
NÃO precedidos por qualquer uma dessas letras.fonte
(?:[^a-g]|^)m
. Consulte regex101.com/r/jL1iW6/2 para obter um exemplo em execução.Foi assim que consegui o
str.split(/(?<!^)@/)
Node.js. 8 (que não suporta lookbehind):Trabalho? Sim (unicode não testado). Desagradável? Sim.
fonte
seguindo a idéia do Mijoja e tirando dos problemas expostos pelo JasonS, eu tive essa idéia; Eu verifiquei um pouco, mas não tenho certeza de mim mesmo, então uma verificação por alguém mais experiente do que eu em js regex seria ótimo :)
minha saída pessoal:
o princípio é chamar
checker
em cada ponto da cadeia entre dois caracteres, sempre que essa posição for o ponto inicial de:--- qualquer substring do tamanho do que não é desejado (aqui
'ba'
, portanto..
) (se esse tamanho for conhecido; caso contrário, talvez seja mais difícil fazer isso)--- --- ou menor que isso, se for o começo da string:
^.?
e, depois disso,
--- o que deve ser realmente procurado (aqui
'll'
).A cada chamada de
checker
, haverá um teste para verificar se o valor anteriorll
não é o que não queremos (!== 'ba'
); se for esse o caso, chamamos outra função, e terá que ser essa (doer
) que fará as alterações em str, se o objetivo for esse, ou mais genericamente, que entrará os dados necessários para processar manualmente os resultados da digitalização destr
.aqui, alteramos a sequência, de modo que precisamos manter um rastro da diferença de comprimento para compensar os locais dados por
replace
, todos calculadosstr
, os quais nunca mudam.Como as seqüências primitivas são imutáveis, poderíamos ter usado a variável
str
para armazenar o resultado de toda a operação, mas pensei que o exemplo, já complicado pelas substituições, seria mais claro com outra variável (str_done
).Eu acho que, em termos de desempenho, deve ser bem duro: todas essas substituições inúteis de '' into '',
this str.length-1
tempos, mais aqui a substituição manual por doer, o que significa muito fatiamento ... provavelmente neste caso específico acima ser agrupados, cortando a corda apenas uma vez em pedaços ao redor de onde queremos inseri -la[match]
e inserindo -.join()
a em[match]
si mesma.a outra coisa é que eu não sei como ele lidaria com casos mais complexos, ou seja, valores complexos para o lookback por trás ... o comprimento talvez seja o dado mais problemático a ser obtido.
e, no
checker
caso de várias possibilidades de valores indesejados para $ behind, teremos que fazer um teste com mais uma regex (ser armazenado em cache (criado) forachecker
é o melhor, para evitar o mesmo objeto de regex a ser criado a cada pedidochecker
) para saber se é ou não o que procuramos evitar.espero ter sido claro; se não, não hesite, tentarei melhor. :)
fonte
Usando seu caso, se você deseja substituir
m
por algo, por exemplo, convertê-lo para maiúsculasM
, você pode negar o conjunto no grupo de captura.combinar
([^a-g])m
, substitua por$1M
([^a-g])
corresponderá a qualquer caractere que não esteja (^
) noa-g
intervalo e o armazenará no primeiro grupo de captura, para que você possa acessá-lo com$1
.Assim, encontramos
im
emjim
e substituí-lo comiM
o que resulta emjiM
.fonte
Como mencionado anteriormente, o JavaScript permite olhar para trás agora. Em navegadores mais antigos, você ainda precisa de uma solução alternativa.
Aposto que não há como encontrar uma expressão regular sem olhar para trás que produza exatamente o resultado. Tudo o que você pode fazer é trabalhar com grupos. Suponha que você tenha uma regex
(?<!Before)Wanted
, ondeWanted
é a regex que você deseja corresponder eBefore
é a regex que conta o que não deve preceder a correspondência. O melhor que você pode fazer é negar a regexBefore
e usá-laNotBefore(Wanted)
. O resultado desejado é o primeiro grupo$1
.No seu caso,
Before=[abcdefg]
é fácil negarNotBefore=[^abcdefg]
. Então, o regex seria[^abcdefg](m)
. Se você precisar da posição deWanted
, também deverá agruparNotBefore
, para que o resultado desejado seja o segundo grupo.Se as correspondências do
Before
padrão tiverem um comprimento fixon
, ou seja, se o padrão não contiver tokens repetitivos, você poderá evitar negar oBefore
padrão e usar a expressão regular(?!Before).{n}(Wanted)
, mas ainda precisará usar o primeiro grupo ou usar a expressão regular(?!Before)(.{n})(Wanted)
e usar o segundo grupo. Neste exemplo, o padrãoBefore
realmente tem um comprimento fixo, ou seja, 1; portanto, use o regex(?![abcdefg]).(m)
ou(?![abcdefg])(.)(m)
. Se você estiver interessado em todas as correspondências, adicione ag
sinalização, veja meu snippet de código:fonte
Isso efetivamente faz
Exemplo de pesquisa e substituição
Observe que a string look-behind negativa deve ter 1 caractere para que isso funcione.
fonte
"m".match(/[^a-g]m/)
criançasnull
também. Também quero o "m" nesse caso./(?![abcdefg])[^abcdefg]m/gi
sim, isso é um truque.fonte
(?![abcdefg])
é totalmente redundante, pois[^abcdefg]
já faz seu trabalho para impedir a correspondência desses caracteres.