Cela peut sembler une question stupide, mais j'ai eu une longue discussion avec certains de mes collègues développeurs et cela semblait être une chose amusante à penser.
Alors; quelle est votre pensée - à quoi ressemble un Regex, qui ne sera jamais égalé par aucune chaîne, jamais!
Edit : Pourquoi je veux ça? Eh bien, d'une part parce que je trouve intéressant de penser à une telle expression et d'autre part parce que j'en ai besoin pour un script.
Dans ce script, je définis un dictionnaire comme Dictionary<string, Regex>
. Cela contient, comme vous le voyez, une chaîne et une expression.
Sur la base de ce dictionnaire, je crée des méthodes qui utilisent toutes ce dictionnaire comme référence uniquement sur la façon dont elles doivent faire leur travail, l'une d'elles compare les expressions régulières à un fichier journal analysé.
Si une expression correspond, une autre Dictionary<string, long>
est ajoutée une valeur qui est renvoyée par l'expression. Donc, pour attraper tous les messages de journal qui ne correspondent pas à une expression dans le dictionnaire, j'ai créé un nouveau groupe appelé "inconnu".
À ce groupe, tout ce qui ne correspond à rien d'autre est ajouté. Mais pour éviter que l'expression "inconnue" ne corresponde (par accident) à un message de journal, j'ai dû créer une expression qui ne correspond certainement jamais, quelle que soit la chaîne que je lui donne.
Ainsi, là vous avez ma raison pour cette "pas une vraie question" ...
la source
Réponses:
C'est en fait assez simple,
bien que cela dépende de l'implémentation / flags*:Correspondra à un caractère
a
après la fin de la chaîne. Bonne chance.AVERTISSEMENT:
cette expression est coûteuse - elle analysera toute la ligne, trouvera l'ancre de fin de ligne et ne trouvera alors pas le
a
et retournera une correspondance négative. (Voir le commentaire ci-dessous pour plus de détails.)* À l'origine, je n'ai pas beaucoup réfléchi à l'expression rationnelle en mode multiligne, où
$
correspond également à la fin d'une ligne. En fait, il correspondrait à la chaîne vide juste avant la nouvelle ligne , donc un caractère ordinaire commea
ne peut jamais apparaître après$
.la source
$a
. Son équivalent Perl$(?:a)
est également très lentperl -Mre=debug -e'$_=a x 50; /$(?:a)/'
.timeit
etpython3
.$a
correspondra au texte littéral$a
, car il$
n'est pas valide en tant qu'ancre dans ce modèle.Effet de levier
negative lookahead
:cette ER est une contradiction dans les termes et ne correspondra donc jamais à rien.
REMARQUE:
en Python, re.match () ajoute implicitement une ancre de début de chaîne (
\A
) au début de l'expression régulière. Cette ancre est importante pour les performances: sans elle, toute la chaîne sera scannée. Ceux qui n'utilisent pas Python voudront ajouter l'ancre explicitement:la source
(?=x)(?!x)
et ainsi de suite (concaténations de lookaheads contradictoires, et même pour les lookbehinds), et beaucoup de ceux-ci fonctionnent également pour des valeurs arbitraires dex
(lookbehinds needx
s qui correspondent à des chaînes de longueur fixe).r'a\bc'
:, à la recherche d'une limite de mot immédiatement entourée de lettres des deux côtés (variante: caractères non-mots sur des deux côtés).perl -Mre=debug -e'$_=x x 8; /(?!x)x/'
. Vous pouvez le rendre plus rapide en l'ancrant au début\A(?!x)x
ou à la fin(?!x)x\z
.perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Celui qui a été manqué:
Il ne peut pas correspondre car la chaîne vide ne contient pas de limite de mot. Testé en Python 2.5.
la source
\`\b\'
fonctionne, ce qui remplace la syntaxe Emacs par "début / fin de texte" (par opposition à "début / fin de la ligne ").regardez autour de vous:
(?=a)b
Pour les débutants en regex: Le regard positif vers l'avant
(?=a)
garantit que le caractère suivant esta
, mais ne change pas l'emplacement de recherche (ou n'inclut pas le «a» dans la chaîne correspondante). Maintenant que le caractère suivant est confirméa
, la partie restante de l'expression régulière (b
) ne correspond que si le caractère suivant estb
. Ainsi, cette expression régulière ne correspond que si un caractère est à la foisa
etb
en même temps.la source
a\bc
, où\b
est une expression de largeur nulle qui correspond à la limite du mot.Il ne peut pas apparaître au milieu d'un mot, ce à quoi nous le forçons.
la source
a
dans le texte.$.
.^
$.^
(?!)
la source
^
n'a une signification spéciale que comme premier caractère d'une expression$
régulière , et n'a qu'une signification spéciale à la fin d'une expression rationnelle, à moins que l'expression régulière ne soit une expression multiligne./$./
signifie quelque chose de complètement différent. Cela signifie correspondre à la valeur actuelle de$.
(numéro de ligne d'entrée) ./$(.)/
Peut même correspondre à quelque chose si vous avez écrituse re '/s';
avant. (perl -E'say "\n" =~ /$(.)/s || 0'
)^
et$
ne sont spéciaux qu'au début et à la fin (respectivement) du modèle, donc aucun de$.
ou.^
ou$.^
ne fonctionnerait.(?!)
est une fonctionnalité Perl / PCRE, je crois.Correspondance maximale
Au moins un
a
suivi de n'importe quel nombre dea
, sans retour en arrière. Ensuite, essayez de faire correspondre un autrea
.ou sous-expression indépendante
Cela équivaut à insérer
a+
une sous-expression indépendante, suivie d'une autrea
.la source
Perl 5.10 prend en charge les mots de contrôle spéciaux appelés "verbes", qui sont placés en
(*...)
séquence. (Comparez avec(?...)
une séquence spéciale.) Parmi eux, il comprend le(*FAIL)
verbe qui revient immédiatement de l'expression régulière.Notez que les verbes sont également implémentés dans PCRE peu de temps après, vous pouvez donc les utiliser en PHP ou dans d'autres langues en utilisant également la bibliothèque PCRE. (Vous ne pouvez pas en Python ou Ruby, cependant. Ils utilisent leur propre moteur.)
la source
\b
correspond aux limites de mot - la position entre une lettre et une non-lettre (ou la limite de chaîne).\B
est son complément - il correspond à la position entre deux lettres ou entre des non-lettres.Ensemble, ils ne peuvent correspondre à aucune position.
Voir également:
la source
^\B\b
. Dans les langues où «début de texte» et «début de ligne» ont une syntaxe différente, vous voudrez utiliser la syntaxe «début de texte», sinon vous testerez chaque ligne. (par exemple dans Emacs, ce serait\`\B\b
ou"\\`\\B\\b"
.)^
est problématique dans certaines syntaxes d'expression régulière (par exemple POSIX BRE) où il^
n'y a qu'une ancre quand c'est le premier caractère du modèle, et correspond autrement à un^
caractère littéral .:)
- c'est une question non pratique, où le but était de trouver une réponse intéressante - pas une réponse efficace. Cela dit, le modèle peut être rejeté dans le temps de ligne (avec la taille de la chaîne cible), donc ce n'est pas mauvais pour une expression régulière - la plupart des modèles ici sont les mêmes, et^
peuvent même être linéaires s'il n'est pas optimisé.Cela semble fonctionner:
la source
$.
. Dans ce cas, vous devez recourir à$(.)
ou de manière plus équivalente$(?:.)
.$.
correspondra à un littéral$
suivi de n'importe quel caractère, car il$
n'est pas valide en tant qu'ancre dans ce modèle.Que diriez-vous
$^
ou peut(?!)
- être ?la source
^
correspond le début et$
la fin d'une ligne.(?!)
- une recherche négative pour une chaîne vide. Mais certaines versions de regex traiteront également cela comme une erreur de syntaxe.$^
correspondra à ces caractères littéraux, car les caractères ne sont pas valides en tant qu'ancres (c'est-à-dire que la raison même pour laquelle vous avez utilisé le modèle l'Le plus rapide sera:
'a' peut être n'importe quel caractère non spécial ('x', 'y'). L'implémentation de Knio est peut-être un peu plus pure, mais celle-ci sera plus rapide pour toutes les chaînes ne commençant pas par le caractère que vous choisissez au lieu de «a» car il ne correspondra pas après le premier caractère plutôt qu'après le second dans ces cas.
la source
^
est spécial uniquement en tant que premier caractère et de même avec$
. Avec n'importe quel outil Unix, cette expression rationnelle va correspondre à tout ce qui contient la chaîne littéralea^
.>^
.Python ne l'acceptera pas, mais Perl:
Cette regex devrait (théoriquement) essayer de faire correspondre un nombre infini (pair) de
w
s, parce que le premier groupe (les()
s) revient en lui-même. Perl ne semble pas émettre d'avertissements, même soususe strict; use warnings;
, donc je suppose que c'est au moins valide, et mes tests (minimaux) ne correspondent à rien, donc je le soumets à votre critique.la source
perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
[^\d\D]
ou(?=a)b
oua$a
oua^a
la source
Cela ne fonctionnera pas pour Python et de nombreux autres langages, mais dans une expression régulière Javascript,
[]
c'est une classe de caractères valide qui ne peut pas être mise en correspondance. Ainsi, ce qui suit devrait échouer immédiatement, quelle que soit l'entrée:Je l'aime mieux que
/$a/
parce que pour moi, il communique clairement son intention. Et quant au moment où vous en auriez besoin, j'en avais besoin parce que j'avais besoin d'une solution de secours pour un modèle compilé dynamiquement basé sur l'entrée utilisateur. Lorsque le modèle n'est pas valide, je dois le remplacer par un modèle qui ne correspond à rien. Simplifié, cela ressemble à ceci:la source
Tous les exemples impliquant un correcteur de limites suivent la même recette. Recette:
Prenez l'un des concordants de limite: ^, $, \ b, \ A, \ Z, \ z
Faites le contraire de ce à quoi ils sont destinés
Exemples:
^ et \ A sont destinés au début donc ne les utilisez pas au début
\ b correspond à une limite de mot donc utilisez-le entre
$, \ Z et \ z sont destinés à la fin donc ne les utilisez pas à la fin
D'autres impliquent l'utilisation d'anticipation et d'anticipation qui fonctionnent également avec la même analogie: si vous donnez une anticipation positive ou négative suivie de quelque chose de contraire
Si vous donnez un regard positif ou négatif en arrière après quelque chose de contraire
Leur pourrait être plus un tel modèle et plus de telles analogies.
la source
Tant de bonnes réponses!
Semblable à la réponse de @ nivk, j'aimerais partager la comparaison des performances de Perl pour différentes variantes de regex sans correspondance.
Vitesse Regex:
Vitesse Regex:
(Ubuntu sur Intel i5-3320M, noyau Linux 4.13, Perl 5.26)
la source
je crois que
couvre même les cas où l'expression régulière comprend des indicateurs comme MULTILINE, DOTALL etc.
Je crois (mais je ne l'ai pas comparé) que quelle que soit la longueur (> 0) de la chaîne entre
\Z
et\A
, le temps de défaillance doit être constant.la source
ou
Avec PCRE et PERL, vous pouvez utiliser ce verbe de contrôle de retour arrière qui force le modèle à échouer immédiatement.
la source
Après avoir vu certaines de ces bonnes réponses, le commentaire de @ arantius (concernant le timing
$x
vsx^
vs(?!x)x
) sur la réponse actuellement acceptée m'a donné envie de chronométrer certaines des solutions données jusqu'à présent.En utilisant la norme de ligne 275k de @ arantius, j'ai exécuté les tests suivants en Python (v3.5.2, IPython 6.2.1).
TL; DR:
'x^'
et'x\by'
sont les plus rapides d'un facteur d'au moins ~ 16, et contrairement à la conclusion de @ arantius,(?!x)x
étaient parmi les plus lents (~ 37 fois plus lents). La question de la vitesse dépend donc certainement de la mise en œuvre. Testez-le vous-même sur votre système prévu avant de vous engager si la vitesse est importante pour vous.MISE À JOUR: Il y a apparemment un grand écart entre le timing
'x^'
et'a^'
. Veuillez consulter cette question pour plus d'informations, et la modification précédente pour les timings plus lents aveca
au lieu dex
.La première fois que j'ai exécuté ceci, j'ai oublié de
r
aw les 3 dernières expressions, donc a'\b'
été interprété comme'\x08'
, le caractère de retour arrière. Cependant, à ma grande surprise,'a\x08c'
c'était plus rapide que le résultat le plus rapide précédent! Pour être honnête, cela correspondra toujours à ce texte, mais je pensais que cela valait la peine de le noter car je ne sais pas pourquoi c'est plus rapide.Mon fichier de test a été créé en utilisant une formule pour "... Contenu lisible et aucune ligne en double" (sur Ubuntu 16.04):
la source
\B\b
est horriblement défectueux en termes de performances (comme tout modèle qui n'est pas ancré à une position, mais ce modèle est particulièrement mauvais). Essayez^\B\b
plutôt l' analyse comparative .Regex vide
Le meilleur regex pour ne jamais correspondre à quoi que ce soit est un regex vide. Mais je ne suis pas sûr que tous les moteurs de regex accepteront cela.
Regex impossible
L'autre solution est de créer une regex impossible. J'ai trouvé que le
$-^
calcul ne prend que deux étapes, quelle que soit la taille de votre texte ( https://regex101.com/r/yjcs1Z/1 ).Pour référence:
$^
et$.
prenez 36 étapes pour calculer -> O (1)\b\B
prend 1507 étapes sur mon échantillon et augmente avec le nombre de caractères dans votre chaîne -> O (n)Fil de discussion plus populaire sur cette question:
la source
Peut être ça?
la source
re.compile('$.+^', re.MULTILINE|re.DOTALL).search('a\nb\nc\n')
renvoie un objet de correspondance correspondant au b et au c (et tous les sauts de ligne adjacents et intermédiaires). L'approche par anticipation négative que je recommande fonctionne (c'est-à-dire qu'elle ne correspond à rien) pour toute combinaison d'indicateurs avec laquelle elle pourrait être compilée.$
et^
./\z.+\A/
(voir perldoc perlre ). Cela empêche le mode multiligne et simple ligne (use re '/ms'
) de l'affecter.et remplacez ... par tous les symboles imprimables;). C'est pour un fichier texte.
la source
[^\x00-\xFF]+
(pour les implémentations basées sur l'octet).[^\s\S]
. Mais comme Ferdinand Beyer l'a déjà dit, cela correspondrait à une chaîne vide.*
; laissez-le désactivé ou remplacez-le par+
, et il doit correspondre à au moins un caractère. Si la classe exclut tous les caractères possibles, elle ne peut rien correspondre.Qu'en est-il au lieu de regex, utilisez simplement une instruction if toujours fausse? En javascript:
la source
Une solution portable qui ne dépendra pas de l'implémentation de l'expression rationnelle consiste simplement à utiliser une chaîne constante dont vous êtes sûr qu'elle n'apparaîtra jamais dans les messages du journal. Par exemple, créez une chaîne basée sur les éléments suivants:
Bien sûr, ce n'est pas un défi intellectuel, mais plutôt une programmation de ruban adhésif .
la source
Crée un modèle contenant uniquement des caractères alphanumériques et '
-
' (dont aucun n'est des caractères spéciaux regex) mais il est statistiquement impossible que la même chaîne soit apparue n'importe où auparavant (car c'est tout l'intérêt d'un GUID).la source