Regex para la cadena que no termina con el sufijo dado

190

No he podido encontrar una expresión regular adecuada para que coincida con cualquier cadena que no termine con alguna condición. Por ejemplo, no quiero hacer coincidir nada que termine con un a.

Esto coincide

b
ab
1

Esto no coincide

a
ba

Sé que la expresión regular debería terminar $para marcar el final, aunque no sé qué debería precederla.

Editar : La pregunta original no parece ser un ejemplo legítimo para mi caso. Entonces: ¿cómo manejar más de un personaje? ¿Di algo que no termine con ab?

He podido solucionar esto, usando este hilo :

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

Aunque la desventaja de esto es que no coincide con una cadena de un carácter.

Menno
fuente
55
Esto no es un duplicado de la pregunta vinculada: la comparación solo con el final requiere una sintaxis diferente a la coincidencia en cualquier lugar dentro de una cadena. Solo mira la respuesta superior aquí.
jaustin
Estoy de acuerdo, esto no es un duplicado de la pregunta vinculada. Me pregunto cómo podemos eliminar las "marcas" anteriores.
Alan Cabrera
No hay tal enlace que pueda ver.
Alan Cabrera

Respuestas:

252

No nos da el idioma, pero si su soporte de sabor regex mira detrás de la afirmación , esto es lo que necesita:

.*(?<!a)$

(?<!a)es una afirmación de retrospectiva negada que garantiza que antes del final de la cadena (o fila con mmodificador), no haya el carácter "a".

Verlo aquí en RegExr

También puede extender esto fácilmente con otros caracteres, ya que esto busca la cadena y no es una clase de caracteres.

.*(?<!ab)$

Esto coincidiría con cualquier cosa que no termine con "ab", míralo en Regexr

Stema
fuente
1
No conozco RegexPAL, pero las expresiones regulares son diferentes en todos los idiomas y las afirmaciones retrospectivas son una característica avanzada que no es compatible con todos.
Stema
77
regexpal es un javascript basado probador de expresiones regulares y javascript no es compatible con las aserciones hacia atrás que es triste
Hamza
Lookbehinds no son compatibles con regexr (javascript)
Stealth Rabbi
1
La falta de mirar atrás en JS me hace llorar. Si está haciendo el lado del servidor, aunque probablemente pueda usar el módulo PCRE en NPM o similar para usarlos directamente (es un conjunto de enlaces, por lo que no creo que pueda usarlo en la parte delantera)
Eirik Birkeland
Más tipos de afirmaciones anticipadas / retrospectivas: stackoverflow.com/q/2973436/12484
Jon Schneider
76

Use el símbolo no ( ^):

.*[^a]$

Si coloca el ^símbolo al principio de los corchetes, significa "todo excepto las cosas entre corchetes". $es simplemente un ancla para el final.

Para varios personajes , solo póngalos todos en su propio conjunto de caracteres:

.*[^a][^b]$
tckmn
fuente
1
+1, con la advertencia de que esto no coincide con la cadena vacía (que puede o no ser como se pretendía), por lo que el significado es más bien "cualquier carácter que no esté entre corchetes".
Fred Foo
3
@ 0A0D: una cadena que contiene espacios en blanco no es una cadena vacía.
Fred Foo
77
@ 0A0D En realidad, eso no está en debate, eso es un hecho
tckmn
8
@Doorknob: eso no coincide aeo cb.
Fred Foo
1
Nop, esto tampoco permitiría "acb".
Menno
49

Para buscar archivos que no terminen con ".tmp" usamos la siguiente expresión regular:

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

Probado con el Regex Tester da el siguiente resultado:

ingrese la descripción de la imagen aquí

Las cinco
fuente
1
Esto es interesante, ¿alguna idea de por qué funciona y por qué ^.*(?![.]tmp$)no?
Łukasz Zaroda
44
Su temprano .*ya coincide con toda la cadena, por lo que la exclusión restante ya no funciona.
FiveO
Para mis propósitos, esto funcionó y las otras respuestas no. ¡Gracias!
David Moritz
8
.*[^a]$

la expresión regular anterior coincidirá con las cadenas que no terminan en a.

Kent
fuente
Extendí mi pregunta ya que el ejemplo original no parecía coincidir completamente con mi caso. ¿Puedes resolverlo?
Menno
5

Prueba esto

/.*[^a]$/

El []denota una clase de caracteres, y los ^invierte la clase de caracteres para que coincida con todo menos una a.

JesperE
fuente
1

La pregunta es antigua pero no pude encontrar una solución mejor. Publico la mía aquí. Busque todas las unidades USB pero no enumere las particiones , eliminando así la "parte [0-9]" de los resultados. Terminé haciendo dos grep, el último niega el resultado:

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

Esto resulta en mi sistema:

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

Si solo quiero las particiones que podría hacer:

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

Donde consigo:

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

Y cuando lo hago:

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

Yo obtengo:

/dev/sdb
tombert
fuente
1

La respuesta aceptada está bien si puedes usar lookarounds. Sin embargo, también hay otro enfoque para resolver este problema.

Si miramos la expresión regular ampliamente propuesta para esta pregunta:

.*[^a]$

Encontraremos que casi funciona. No acepta una cadena vacía, lo que puede ser un poco incómodo. Sin embargo, este es un problema menor cuando se trata de un solo personaje. Sin embargo, si queremos excluir una cadena completa, por ejemplo, "abc", entonces:

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

no lo haré No aceptará ac, por ejemplo.

Sin embargo, hay una solución fácil para este problema. Simplemente podemos decir:

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

o versión más generalizada:

.{,n-1}$|.*[^firstchar][^secondchar]$ donde n es la longitud de la cadena que desea prohibir (porque abces 3), y firstchar, secondchar... son los primeros, segundos ... enésimos caracteres de su cadena (porque abcsería a, entonces b, entonces c).

Esto proviene de una simple observación de que una cadena que es más corta que el texto que no prohibiremos no puede contener este texto por definición. Por lo tanto, podemos aceptar cualquier cosa que sea más corta ("ab" no es "abc"), o cualquier cosa que podamos aceptar pero sin el final.

Aquí hay un ejemplo de búsqueda que eliminará todos los archivos que no sean .jpg:

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

MatthewRock
fuente
.{,2}$|.*[^a][^b][^c]$no coincideccc
psalaets
0

Cualquier cosa que coincida con algo que termine con un --- .*a$Entonces, cuando coincida con la expresión regular, niegue la condición o, alternativamente, también puede hacer .*[^a]$donde [^a]significa cualquier cosa que seanot a

Cuenta
fuente
0

Si está utilizando grepo sedla sintaxis será un poco diferente. Tenga en cuenta que el [^a][^b]método secuencial no funciona aquí:

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, estoy encontrando los mismos resultados en Regex101 , que creo que es la sintaxis de JavaScript.

Malo: https://regex101.com/r/MJGAmX/2
Bueno: https://regex101.com/r/LzrIBu/2

abalter
fuente