web-dev-qa-db-fra.com

Regex pour une chaîne ne se terminant pas par un suffixe donné

Je n'ai pas été en mesure de trouver une expression rationnelle propre à correspondre à une chaîne not se terminant par une condition. Par exemple, je ne veux pas faire correspondre quoi que ce soit qui se termine par un a.

Cela correspond à

b
ab
1

Cela ne correspond pas

a
ba

Je sais que la regex devrait se terminer par $ pour marquer la fin, bien que je ne sache pas ce qui devrait la précéder.

Edit: La question initiale ne semble pas être un exemple légitime pour mon cas. Alors: comment gérer plus d'un personnage? Dis quelque chose qui ne se termine pas par ab?

J'ai pu résoudre ce problème en utilisant ce fil de discussion :

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

L’inconvénient est que cela ne correspond pas à la chaîne d’un caractère.

129
Menno

Vous ne nous donnez pas le langage, mais si votre style regex supporte regarde derrière l'assertion , voici ce dont vous avez besoin:

.*(?<!a)$

(?<!a) est une assertion de recherche négative qui assure qu'avant la fin de la chaîne (ou de la ligne avec le modificateur m), il n'y a pas le caractère "a".

Voir ici sur Regexr

Vous pouvez aussi facilement l'étendre avec d'autres caractères, puisque cette vérification n'est pas une classe de caractères.

.*(?<!ab)$

Cela correspond à tout ce qui ne se termine pas par "ab", voyez-le sur Regexr

169
stema

Utilisez le symbole not (^):

.*[^a]$

Si vous mettez le symbole ^ au début des crochets, cela signifie "tout sauf les éléments entre crochets". $ est simplement une ancre à la fin.

Pour plusieurs caractères , il suffit de les mettre tous dans leur propre jeu de caractères:

.*[^a][^b]$
52
Doorknob

Pour rechercher des fichiers ne se terminant pas par ".tmp", nous utilisons les expressions régulières suivantes: 

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

Testé avec le testeur Regex donne le résultat suivant: 

enter image description here

30
FiveO
.*[^a]$

l'expression régulière ci-dessus correspond aux chaînes qui ne se terminent pas par a.

7
Kent

Essaye ça

/.*[^a]$/

Le [] désigne une classe de caractères et le ^ inverse la classe de caractères pour qu'elle corresponde à tout sauf une a

3
JesperE

Si vous utilisez grep ou sed, la syntaxe sera un peu différente. Notez que la méthode séquentielle [^a][^b] ne fonctionne pas ici:

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, je trouve les mêmes résultats dans Regex101 , qui, je pense, est la syntaxe JavaScript.

Mauvais: https://regex101.com/r/MJGAmX/2
Bon: https://regex101.com/r/LzrIBu/2

0
abalter

La question est ancienne mais je ne pouvais pas trouver une meilleure solution que je poste la mienne ici. Recherche tous les lecteurs USB mais ne répertorie pas les partitions , supprimant ainsi la "partie [0-9]" des résultats. J'ai fini par faire deux grep, le dernier annule le résultat:

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

Cela se traduit sur mon système:

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

Si je veux seulement les partitions que je pourrais faire:

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

Où j'arrive:

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

Et quand je le fais:

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

Je reçois:

/dev/sdb
0
tombert

La réponse acceptée est acceptable si vous pouvez utiliser des lookarounds. Cependant, il existe également une autre approche pour résoudre ce problème.

Si nous regardons la regex largement proposée pour cette question:

.*[^a]$

Nous constaterons que cela fonctionne presque. Il n'accepte pas une chaîne vide, ce qui pourrait être un peu inconvinient. Cependant, il s’agit d’un problème mineur s’agissant d’un seul caractère. Cependant, si nous voulons exclure toute la chaîne, par ex. "abc", alors:

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

ne fera pas. Il n'acceptera pas ca, par exemple.

Il existe cependant une solution simple à ce problème. Nous pouvons simplement dire:

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

ou version plus généralisée:

.{,n-1}$|.*[^firstchar][^secondchar]$ où n est la longueur de la chaîne que vous voulez interdire (pour abc c'est 3), et firstchar, secondchar, ... sont les premier, deuxième ... nièmes caractères de votre chaîne (pour abc ce serait a, alors b, puis c).

Cela vient d'une simple observation qu'une chaîne plus courte que le texte que nous n'interdirons pas ne peut pas contenir ce texte par définition. Nous pouvons donc accepter tout ce qui est plus court ("ab" n'est pas "abc"), ou tout ce qui est assez long pour que nous puissions l'accepter mais sans la fin.

Voici un exemple de find qui supprimera tous les fichiers qui ne sont pas .jpg:

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

0
MatthewRock

Tout ce qui correspond à quelque chose qui se termine par --- .*a$ Ainsi, lorsque vous correspondez à l'expression régulière, annulez la condition .__ ou vous pouvez également faire .*[^a]$[^a] signifie tout ce qui est not a

0
Bill