67 votes

Expression régulière de lookahead négatif

Je veux faire correspondre toutes les chaînes de caractères se terminant par ".htm", sauf si elles se terminent par "foo.htm". Je me débrouille généralement bien avec les expressions régulières, mais les expressions négatives me laissent perplexe. Pourquoi cela ne fonctionne-t-il pas ?

/(?!foo)\.htm$/i.test("/foo.htm");  // returns true. I want false.

Que devrais-je utiliser à la place ? Je pense que j'ai besoin d'un "regard négatif". derrière "(si JavaScript supportait une telle chose, mais je sais qu'il ne le fait pas).

2 votes

Malheureusement, JavaScript ne supporte pas le "lookbehind" dans les expressions régulières.

2 votes

Il est souvent préférable d'avoir une expression régulière plus simple avec une boucle ou deux, plutôt qu'une expression régulière super monstrueuse (d'accord, ce que vous voulez n'est pas super monstrueux, mais le code a tendance à grossir), je dirais même impossible à maintenir.

0 votes

Ce n'est peut-être pas opportun, mais pour expliquer pourquoi cela ne fonctionne pas : Votre regexp n'est pas un 0-width, ce qui signifie qu'en javascript, cela se traduit par "Match '.htm' mais pas s'il commence par 'foo'", puisque ".htm" ne commencera jamais par "foo", cela ne fonctionnera pas. Le lookahead négatif signifie "à ce stade, exclure les correspondances où ce négatif est vrai ici", mais il ne consomme pas réellement la chaîne.

98voto

ridgerunner Points 14773

Le problème est assez simple en fait. Ceci va le faire :

/^(?!.*foo\.htm$).*\.htm$/i

1 votes

+1. Non seulement lookbehind n'est pas nécessaire, mais il ne serait pas le meilleur outil pour cela s'il était disponible.

0 votes

Une technique si utile !

6 votes

Pouvez-vous expliquer ce qui se passe ? Je vois que vous avez un jeton de début de ligne (^) mais deux jetons de fin de ligne ($). Comment cela permet-il de faire fonctionner le lookahead négatif ?

18voto

NickC Points 13729

Ce que vous décrivez (votre intention) est négatif. look-behind et Javascript n'a pas de support pour les "look-behinds".

Les looks-aheads regardent vers l'avant à partir du caractère sur lequel ils sont placés - et vous l'avez placé avant le personnage de l'image. . . Donc, ce que vous avez, c'est de dire "tout ce qui se termine en .htm pour autant que les trois premiers caractères commençant à cette position ( .ht ) ne sont pas foo ", ce qui est toujours vrai.

En général, la solution de remplacement pour les contrôles négatifs est d'apparier plus que ce dont vous avez besoin, et de n'extraire que la partie dont vous avez réellement besoin. C'est une méthode approximative, et en fonction de votre situation précise, vous pouvez probablement trouver une autre solution, mais quelque chose comme ceci :

// Checks that the last 3 characters before the dot are not foo:
/(?!foo).{3}\.htm$/i.test("/foo.htm"); // returns false

1 votes

Tu m'as donné assez pour me permettre de faire le reste du chemin. Cela fonctionne pour tous mes cas de test : /(^.{0,2}|(?!foo).{3})\.htm$/i

4 votes

+1 Excellente explication. Cependant, /(?!foo).{3}\.htm$/i ne correspondra pas à un nom ayant moins de trois caractères, c'est-à-dire que a.htm . En voici un qui les aura tous : /^(?!.*foo\.htm$).*\.htm$/i

2voto

Floern Points 11484

Comme nous l'avons mentionné, JavaScript ne prend pas en charge les assertions négatives de type "look-behind".

Mais tu pourrais utiliser un workaroud :

/(foo)?\.htm$/i.test("/foo.htm") && RegExp.$1 != "foo";

Cela correspondra à tout ce qui se termine par .htm mais il stockera "foo" en RegExp.$1 s'il correspond foo.htm pour que vous puissiez le traiter séparément.

0 votes

2voto

petho Points 446

Comme Renesis l'a mentionné, "lookbehind" n'est pas pris en charge par JavaScript, il suffit donc d'utiliser deux regexps en combinaison :

!/foo\.htm$/i.test(teststring) && /\.htm$/i.test(teststring)

0 votes

Lookahead est supporté en JavaScript.

0 votes

Thx :) je viens juste de me rappeler d'un an, probablement que ma mémoire ne me sert pas tant que ça

0voto

ngn Points 2820

Vous pourriez imiter le lookbehind négatif avec quelque chose comme /(.|..|.*[^f]..|.*f[^o].|.*fo[^o])\.htm$/ mais une approche programmatique serait préférable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X