Regex para a sequência que não termina com o sufixo fornecido


190

Não consegui encontrar uma regex adequada para corresponder a nenhuma sequência que não termina com alguma condição. Por exemplo, não quero corresponder nada que termine com um a.

Isso corresponde

b
ab
1

Isso não corresponde

a
ba

Eu sei que o regex deve terminar com $para marcar o final, embora eu não saiba o que deve preceder.

Edit : A pergunta original não parece ser um exemplo legítimo para o meu caso. Então: como lidar com mais de um personagem? Diga alguma coisa que não termine com ab?

Eu fui capaz de corrigir isso, usando este segmento :

.*(?:(?!ab).).$

Embora a desvantagem disso seja, ele não corresponde a uma sequência de um caractere.


5
Esta não é uma duplicata da pergunta vinculada - a correspondência apenas no final requer uma sintaxe diferente da correspondência em qualquer lugar dentro de uma string. Basta olhar para a resposta superior aqui.
jaustin

Eu concordo, isso não é uma duplicata da questão vinculada. Gostaria de saber como podemos remover as "marcas" acima?
Alan Cabrera

Não existe esse link que eu possa ver.
Alan Cabrera

Respostas:


252

Você não nos fornece o idioma, mas se o suporte ao sabor de expressão regular estiver por trás da afirmação , é disso que você precisa:

.*(?<!a)$

(?<!a)é uma asserção lookbehind negada que garante que, antes do final da string (ou linha com mmodificador), não haja o caractere "a".

Veja aqui no Regexr

Você também pode estender isso facilmente com outros caracteres, pois essa verificação da cadeia de caracteres e não é uma classe de caracteres.

.*(?<!ab)$

Isso corresponderia a qualquer coisa que não termine com "ab", veja no Regexr


1
Não conheço o RegexPAL, mas os regexes são diferentes em todos os idiomas e as assertivas lookbehind são um recurso avançado que não é suportado por todos.
stema

7
regexpal é um javascript com base tester regex e javascript não suporta afirmações lookbehind que é triste
Hamza

O Lookbehinds não é suportado no regexr (javascript)
Stealth Rabbi

1
A falta de olhar para trás em JS me faz chorar. Se você estiver trabalhando no lado do servidor, provavelmente poderá usar o módulo PCRE no NPM ou similar para usá-los diretamente (é um conjunto de ligações, então acho que você não pode usá-lo no front-end)
Eirik Birkeland

Mais tipos de asserções lookahead / lookbehind: stackoverflow.com/q/2973436/12484
Jon Schneider

76

Use o símbolo not ( ^):

.*[^a]$

Se você colocar o ^símbolo no início dos colchetes, significa "tudo, exceto as coisas entre colchetes". $é simplesmente uma âncora até o fim.

Para vários caracteres , basta colocá-los todos em seu próprio conjunto de caracteres:

.*[^a][^b]$

1
+1, com a ressalva de que isso não corresponde à sequência vazia (que pode ou não ser a pretendida); portanto, o significado é "qualquer caractere que não esteja entre colchetes".
Fred Foo

3
@ 0A0D: uma string contendo espaço em branco não é uma string vazia.
Fred Foo

7
@ 0A0D Na verdade, isso não está em debate, isso é verdade
tckmn

8
@ Doorknob: isso não corresponde aeou cb.
Fred Foo

1
Não, isso também não permitiria "acb".
Menno

49

Para procurar arquivos que não terminem com ".tmp", usamos o seguinte regex:

^(?!.*[.]tmp$).*$

Testado com o Regex Tester fornece o seguinte resultado:

insira a descrição da imagem aqui


1
Isso é interessante, alguma idéia de por que isso funciona e por ^.*(?![.]tmp$)que não?
Łukasz Zaroda

4
Seu início .*já corresponde à cadeia inteira, portanto a exclusão restante não funciona mais.
FiveO

Para meus propósitos, isso funcionou e as outras respostas não. Obrigado!
David Moritz

8
.*[^a]$

a regex acima corresponderá às strings que não terminam com a.


Estendi minha pergunta, pois o exemplo original não parecia corresponder totalmente ao meu caso. Você pode resolver isso?
Menno

5

Tente isto

/.*[^a]$/

A []denota uma classe de caracteres, e as ^inverte a classe de caracteres para corresponder tudo, mas um a.


1

A pergunta é antiga, mas não consegui encontrar uma solução melhor, posto aqui a minha. Encontre todas as unidades USB, mas não liste as partições , removendo a "parte [0-9]" dos resultados. Acabei fazendo dois grep, o último nega o resultado:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -vE "part[0-9]*$"

Isso resulta no meu sistema:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Se eu apenas quero as partições, eu poderia fazer:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -E "part[0-9]*$"

Onde eu recebo:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part1
pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part2

E quando eu faço:

readlink -f /dev/disk/by-path/pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Eu recebo:

/dev/sdb

1

A resposta aceita é boa se você pode usar lookarounds. No entanto, há também outra abordagem para resolver esse problema.

Se olharmos para o regex amplamente proposto para esta pergunta:

.*[^a]$

Veremos que quase funciona. Ele não aceita uma string vazia, o que pode ser um pouco inconviniente. No entanto, esse é um problema menor ao lidar com apenas um personagem. No entanto, se queremos excluir uma string inteira, por exemplo, "abc", então:

.*[^a][^b][^c]$

não vai fazer. Não aceita AC, por exemplo.

Existe uma solução fácil para esse problema. Podemos simplesmente dizer:

.{,2}$|.*[^a][^b][^c]$

ou versão mais generalizada:

.{,n-1}$|.*[^firstchar][^secondchar]$ onde n comprimento da corda que você quer proibir (para é abcque é 3), e firstchar, secondchar... são de primeira, personagens segunda ... enésima de sua seqüência (por abcque seria a, então b, a seguir c).

Isso vem de uma simples observação de que uma string menor que o texto que não proibimos não pode conter esse texto por definição. Portanto, podemos aceitar qualquer coisa que seja mais curta ("ab" não é "abc") ou qualquer coisa que seja longa o suficiente para aceitarmos, mas sem o final.

Aqui está um exemplo de localização que excluirá todos os arquivos que não são .jpg:

find . -regex '.{,3}$|.*[^.][^j][^p][^g]$' -delete


.{,2}$|.*[^a][^b][^c]$não correspondeccc
psalaets 01/09/19

0

Qualquer coisa que corresponda a algo que termine com --- .*a$Então, quando você corresponder à regex, negue a condição ou, alternativamente, você também poderá fazer .*[^a]$onde [^a]significa qualquer coisa que sejanot a


0

Se você estiver usando grepou seda sintaxe será um pouco diferente. Observe que o [^a][^b]método seqüencial não funciona aqui:

balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n'
jd8a
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a]$"
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^b]$"
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^c]$"
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c]$"
jd8a
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c^a]$"

FWIW, estou encontrando os mesmos resultados no Regex101 , que acho que é a sintaxe JavaScript.

Ruim: https://regex101.com/r/MJGAmX/2
Bom: https://regex101.com/r/LzrIBu/2

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.