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.

Menno
fonte
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

stema
fonte
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]$
tckmn
fonte
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

FiveO
fonte
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.

Kent
fonte
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.

JesperE
fonte
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
Tombert
fonte
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

MatthewRock
fonte
.{,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

Conta
fonte
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

abalter
fonte