web-dev-qa-db-fra.com

Expression régulière qui ne contient pas certaines chaînes

J'ai quelque chose comme ça

aabbabcaabda

pour la sélection du groupe minimal enveloppé par a J'ai cette /a([^a]*)a/ qui fonctionne très bien

Mais j'ai un problème avec les groupes encapsulés par aa, où j'aurais besoin de quelque chose comme /aa([^aa]*)aa/ qui ne fonctionne pas, et je ne peux pas utiliser le premier comme /aa([^a]*)aa/, parce que cela se terminerait à la première occurrence de a, ce que je ne veux pas.

Généralement, y a-t-il un moyen, comment dire ne contient pas de chaîne de la même manière que je peux dire ne contient pas de caractère avec [^a]?

Simplement dit, j'ai besoin de aa suivi de n'importe quel caractère sauf séquence aa puis se termine par aa

76
Jakub Arnold

En général, écrire une expression régulière et non contenant une chaîne particulière est une tâche ardue. Nous devions faire cela pour les modèles de calcul - vous prenez un NFA, qui est assez facile à définir, puis vous le réduisez à une expression régulière. L'expression pour les choses ne contenant pas "chat" était d'environ 80 caractères.

Edit: Je viens de finir et oui, c'est:

aa([^a] | a[^a])aa

Ici est un très bref tutoriel. J'en ai trouvé d'excellents auparavant, mais je ne les vois plus.

18
Claudiu

Par la puissance de Google, j'ai trouvé n article de blog de 2007 qui donne la regex suivante qui correspond à une chaîne qui ne contient pas contient un certaine sous-chaîne:

^((?!my string).)*$

Cela fonctionne comme suit: il recherche zéro ou plus (*) caractères (.) Qui ne commencent pas (?! - Négatif lookahead) votre chaîne et il stipule que la chaîne entière doit être composée de tels caractères (en utilisant le ^ et $ ancres). Ou pour le dire autrement:

La chaîne entière doit être composée de caractères ne commençant pas par une chaîne donnée, ce qui signifie que la chaîne ne contient pas la sous-chaîne donnée.

202
Grey Panther

Tout ce dont vous avez besoin est un quantificateur réticent:

regex: /aa.*?aa/

aabbabcaabda   => aabbabcaa

aaaaaabda      => aaaa

aabbabcaabda   => aabbabcaa

aababaaaabdaa  => aababaa, aabdaa

Vous pouvez également utiliser un indicateur négatif, mais dans ce cas, il s'agit simplement d'une manière plus verbeuse de réaliser la même chose. En outre, c'est un peu plus délicat que ce que gpojd a dit. Le lookahead doit être appliqué à chaque position avant que le point puisse utiliser le caractère suivant.

/aa(?:(?!aa).)*aa/

En ce qui concerne l’approche suggérée par Claudiu et Finnw, elle fonctionnera bien si la chaîne sentinelle n’a que deux caractères, mais (comme le reconnaît Claudiu), elle est trop lourde pour des chaînes plus longues.

10
Alan Moore
/aa([^a]|a[^a])*aa/
7
finnw

Je ne suis pas sûr que ce soit une construction standard, mais je pense que vous devriez jeter un coup d'oeil sur "négatif lookahead" (qui écrit: "?!", Sans les guillemets). C'est beaucoup plus facile que toutes les réponses de ce fil, y compris celle acceptée.

Exemple: Regex: "^ (?! 123) [0-9] *\w" Capture toute chaîne commençant par des chiffres suivis de lettres, SAUF SI "ces chiffres" sont 123.

http://msdn.Microsoft.com/en-us/library/az24scfc%28v=vs.110%29.aspx#grouping_constructs (page Microsoft, mais assez complète) pour lookahead/lookbehind

PS: ça marche bien pour moi (.Net). Mais si je me trompe sur quelque chose, s'il vous plaît laissez-nous savoir. Je trouve cette construction très simple et efficace, alors je suis surpris de la réponse acceptée.

6
AFract

Dans le code suivant, je devais remplacer ajouter un paramètre GET à toutes les références aux fichiers JS, SAUF un.

<link rel="stylesheet" type="text/css" href="/login/css/ABC.css" />
<script type="text/javascript" language="javascript" src="/localization/DEF.js"></script>
<script type="text/javascript" language="javascript" src="/login/jslib/GHI.js"></script>
<script type="text/javascript" language="javascript" src="/login/jslib/md5.js"></script>
sendRequest('/application/srvc/EXCEPTION.js', handleChallengeResponse, null);
sendRequest('/application/srvc/EXCEPTION.js",handleChallengeResponse, null);

C'est le Matcher utilisé:

(?<!EXCEPTION)(\.js)

Cela permet de rechercher toutes les occurrences de ".js" et, si elles sont précédées de la chaîne "EXCEPTION", ignorent le résultat du tableau de résultats. Cela s'appelle un lookbehind négatif. Depuis que j'ai passé une journée à découvrir comment faire cela, j'ai pensé que je devrais partager.

4
jsaddwater
".*[^(\\.inc)]\\.ftl$"

Dans Java), tous les fichiers se terminant par ".ftl" mais ne se terminant pas par ".inc.ftl" sont exactement ce que je voulais.

2
twopigs