web-dev-qa-db-fra.com

Existe-t-il une expression régulière pour correspondre à une chaîne qui contient A mais ne contient pas B

Mon problème est que je veux vérifier la chaîne de navigation avec une expression rationnelle pure.

Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13

-> devrait correspondre

Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 

ne doit pas correspondre

ma solution essayée est: /?((?<=Android)(?:[^])*?(?=Mobile))/i mais elle correspond exactement mal.

36
user1061688

Vous utilisez des assertions d'anticipation pour vérifier si une chaîne contient un mot ou non.

Si vous voulez vous assurer que la chaîne contient "Android" à un certain endroit, vous pouvez le faire comme ceci:

^(?=.*Android).*

Vous pouvez également les combiner, pour vous assurer qu'il contient "Android" à un endroit ET "Mobile" à un endroit:

^(?=.*Android)(?=.*Mobile).*

Si vous voulez vous assurer qu'un certain mot n'est pas dans la chaîne, utilisez l'anticipation négative:

^(?=.*Android)(?!.*Mobile).*

Cela nécessiterait que le mot "Android soit dans la chaîne et que le mot" Mobile "ne soit pas autorisé dans la chaîne. Le .* part correspond alors à la chaîne/ligne complète lorsque les assertions au début sont vraies.

Voir ici sur Regexr

66
stema

Je vais juste le casser

if ((m/Android/i) && (m/Safari/i) && !(m/Mobile Safari/i))

Cela dit, en fonction de la saveur regex, vous pouvez combiner cela

if ((m/Android/i) && (m/(?<!Mobile )Safari/i))

ou même

if (m/Android.*(?<!Mobile )Safari/i)

Pour info voir Lookahead/lookbehind


Mise à jour Testé correctement avec l'arôme regex Perl5 (sans doute l'arôme le plus populaire):

Perl -ne 'print "$. yes\n" if m/Android.*(?<!Mobile )Safari/i'

Spectacles:

1 yes

pour l'entrée donnée dans l'OP

2
sehe

Avec certaines implémentations d'expressions régulières, vous pouvez utiliser une assertion lookbehind négative. D'après les documents, un lookbehind négatif écrit comme (?<!...) ne correspond que si la position actuelle dans la chaîne n'est pas précédée d'une correspondance pour ...

Voici un Python montrant comment utiliser le lookbehind négatif avec vos exemples de chaînes:

>>> s = "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13"
>>> bool(re.search(r'Android.*(?<! Mobile) Safari', s))
True

>>> t = "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"
>>> bool(re.search(r'Android.*(?<! Mobile) Safari', t))
False
2
Raymond Hettinger