Un Regex qui ne sera jamais égalé par quoi que ce soit

131

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" ...

Florian Peschka
la source
1
Notez qu'il est très difficile de prouver un négatif.
Lasse V. Karlsen
5
Intéressant. Où utiliseriez-vous une telle regex?
Charlie Salts
1
Je noterai ici pour le compte rendu que la plupart des commentaires ci-dessus, et des réponses à cette question, étaient à l'origine de stackoverflow.com/questions/1845078/… qui est celui que j'ai demandé. Marc Gravell les a fusionnés, ce qui, je pense, rend beaucoup de ces réponses un peu bizarres sans le contexte original précis, au point que certains commentaires ne semblent pas avoir de sens. (Probablement aussi vole aussi de futurs points de répétitions potentiels.) Je suggérerais que des questions avec des antécédents aussi détaillés ne pourraient jamais être des "doubles exacts". Whatever ...
Peter Hansen
2
Cette question a été ajoutée à la FAQ sur les expressions régulières Stack Overflow , sous "Advanced Regex-Fu".
aliteralmind
3
"Notez qu'il est très difficile de prouver un négatif" - c'est largement cru mais tout à fait et évidemment faux ... comme nous l'avons connu au moins depuis qu'Euclid a prouvé qu'il n'y a pas de meilleur prime. Et toute preuve de P est une preuve de la négation de (et non de P). Ce qui est vrai, c'est qu'il est difficile de prouver un universel empirique, positif ou négatif, par exemple «tous les corbeaux sont noirs» ou «aucun corbeau n'est blanc». Les algorithmes sont analytiques et non empiriques, c'est donc une mauvaise application particulièrement mauvaise de la règle bidon. par exemple, une preuve que le motif 'a' ne correspond à aucune chaîne commençant par 'b' n'est pas "très difficile".
Jim Balter

Réponses:

66

C'est en fait assez simple, bien que cela dépende de l'implémentation / flags *:

$a

Correspondra à un caractère aaprè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 aet 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 comme ane peut jamais apparaître après $.

Ferdinand Beyer
la source
50
Cette expression est chère - elle balaiera toute la ligne, trouvera l'ancre de fin de ligne et ne trouvera alors pas le "a" et retournera une correspondance négative. Je vois qu'il faut ~ 480 ms pour numériser un fichier de ligne ~ 275k. L'inverse "a ^" prend à peu près le même temps, même si cela peut sembler plus efficace. En revanche, une anticipation négative n'a besoin de rien scanner: "(?! X) x" (tout ce qui n'est pas suivi d'un x également suivi d'un x, c'est-à-dire rien) prend environ 30 ms, soit moins de 7% du temps. (Mesuré avec l'heure gnu et egrep.)
arantius
1
En Perl, cela correspondra à la valeur actuelle de $a. Son équivalent Perl $(?:a)est également très lent perl -Mre=debug -e'$_=a x 50; /$(?:a)/'.
Brad Gilbert
@arantius, s'il vous plaît voir ma réponse concernant le timing , car j'ai trouvé l'exact opposé mesuré avec timeitet python3.
nivk
Ce n'est pas choquant que six ans et une version majeure de Python puissent changer les choses.
arantius
1
Dans la syntaxe POSIX BRE, $acorrespondra au texte littéral $a, car il $n'est pas valide en tant qu'ancre dans ce modèle.
phils
76

Effet de levier negative lookahead:

>>> import re
>>> x=r'(?!x)x'
>>> r=re.compile(x)
>>> r.match('')
>>> r.match('x')
>>> r.match('y')

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:

\A(?!x)x
Alex Martelli
la source
@Chris, oui - aussi, (?=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 de x(lookbehinds need xs qui correspondent à des chaînes de longueur fixe).
Alex Martelli
1
Semble bien fonctionner. Mais qu'en est-il juste (?!) À la place? Puisque () correspondra toujours, ne serait-il pas garanti (?!) De ne jamais correspondre?
Peter Hansen
2
@Peter, oui, si Python accepte cette syntaxe (et les versions récentes semblent le faire), alors ce serait également contradictoire. Une autre idée (pas tout à fait aussi élégante, mais plus vous avez d'idées, plus vous avez de chances d'en trouver une qui fonctionne sur tous les moteurs RE d'intérêt) 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).
Alex Martelli
1
Fait intéressant, mon original avec un simple littéral que je "sais" n'apparaîtra pas dans mon entrée s'avère être le plus rapide, en Python. Avec une chaîne d'entrée de 5 Mo, et en l'utilisant dans une opération sub (), (?! X) x prend 21% de plus, (?! ()) Est de 16% et ($ ^) 6% de plus. Peut être important dans certains cas, mais pas dans le mien.
Peter Hansen
2
Cela peut être assez lent perl -Mre=debug -e'$_=x x 8; /(?!x)x/'. Vous pouvez le rendre plus rapide en l'ancrant au début \A(?!x)xou à la fin (?!x)x\z. perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Brad Gilbert
43

Celui qui a été manqué:

^\b$

Il ne peut pas correspondre car la chaîne vide ne contient pas de limite de mot. Testé en Python 2.5.

Mark Byers
la source
7
C'est la meilleure réponse. Il n'utilise pas de lookaheads, ne rompt pas avec certaines implémentations de regex, n'utilise pas de caractère spécifique (par exemple 'a'), et échoue dans un maximum de 3 étapes de traitement (selon regex101.com) sans scanner l'ensemble chaîne d'entrée. Ceci est également facile à comprendre en un coup d'œil.
CubicleSoft
1
Cela échoue réellement dans Emacs dans certaines conditions (s'il y a une ligne vide au début ou à la fin du tampon), mais \`\b\'fonctionne, ce qui remplace la syntaxe Emacs par "début / fin de texte" (par opposition à "début / fin de la ligne ").
phils
35

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 est a, 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 est b. Ainsi, cette expression régulière ne correspond que si un caractère est à la fois aet ben même temps.

Amarghosh
la source
30

a\bc, où \best 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.

P Shved
la source
Si votre cas d'utilisation vous permet d'ancrer le modèle au début de la chaîne, alors cette amélioration empêchera le moteur d'expression régulière de rechercher et de tester chaque instance de an adans le texte.
phils
20

$.

.^

$.^

(?!)

Knio
la source
1
Mignonne! Mon subconscient m'a éloigné d'idées comme les trois premières, car elles sont "illégales" ... conceptuellement, mais évidemment pas vers l'expression régulière. Je ne reconnais pas celui (!) ... devra chercher celui-là.
Peter Hansen
1
Bon alors, j'aime la réponse (?!) ... effectivement ce qu'Alex a suggéré. Notez que dans stackoverflow.com/questions/1723182 (souligné par Amarghosh ci-dessus), quelqu'un prétend que "certaines saveurs" de regex considéreraient qu'une erreur de syntaxe. Python l'aime bien cependant. Notez que vos autres suggestions échoueraient toutes avec les modes re.DOTALL | re.MULTILINE en Python.
Peter Hansen
1
Cela a-t-il été testé? J'aurais supposé que cela ^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.
PP.
En fait, en Perl /$./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 écrit use re '/s';avant. ( perl -E'say "\n" =~ /$(.)/s || 0')
Brad Gilbert
Dans la syntaxe POSIX BRE, ^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.
phils
13

Correspondance maximale

a++a

Au moins un asuivi de n'importe quel nombre de a, sans retour en arrière. Ensuite, essayez de faire correspondre un autre a.

ou sous-expression indépendante

Cela équivaut à insérer a+une sous-expression indépendante, suivie d'une autre a.

(?>a+)a
Brad Gilbert
la source
10

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.)

Kang Seonghoon
la source
La documentation pour cela sur perldoc.perl.org/perlre.html#%28%2AFAIL%29-%28%2AF%29 dit "Ce modèle ne correspond à rien et échoue toujours. Il est équivalent à (?!), Mais plus facile à read. En fait, (?!) est optimisé en (* FAIL) en interne. " Intéressant, car (?!) Est ma réponse "pure" préférée jusqu'à présent (même si cela ne fonctionne pas en Javascript). Merci.
Peter Hansen
10
\B\b

\bcorrespond aux limites de mot - la position entre une lettre et une non-lettre (ou la limite de chaîne).
\Best son complément - il correspond à la position entre deux lettres ou entre des non-lettres.

Ensemble, ils ne peuvent correspondre à aucune position.

Voir également:

Kobi
la source
Cela semble être une excellente solution, à condition qu'elle soit ancrée sur un point précis (le début du texte semble judicieux). Si vous ne le faites pas, c'est une solution terrible , car chaque limite non-mot dans le texte sera testée pour voir si elle est suivie d'une limite de mot! Donc, la version raisonnable serait quelque chose comme ^\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\bou "\\`\\B\\b".)
phils
Cela dit, j'ai maintenant noté que le but déclaré de cette question est d'obtenir une expression rationnelle à utiliser dans un groupe, auquel cas ^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 .
phils
@phils - Je pense que vous y réfléchissez trop :)- 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é.
Kobi
Re: optimisations, je suis prêt à ignorer un moteur de regexp qui espère trouver "le début du texte" à n'importe quelle autre position :)
phils
De plus, ce n'est pas une question / réponse si peu pratique - la seule raison pour laquelle je me suis retrouvé ici était de voir si quelqu'un pouvait suggérer une solution plus efficace à la mienne dans le but pratique de configurer une variable Emacs particulière qui nécessitait une valeur d'expression régulière, mais que je voulait désactiver efficacement.
phils
8

Cela semble fonctionner:

$.
Jerry Fernholz
la source
2
C'est similaire à l'exemple de Ferdinand Beyer.
Gumbo
9
Et il correspondra en mode dot-matches-newlines.
Tim Pietzcker
En Perl, cela correspondra au numéro de ligne d'entrée actuel $.. Dans ce cas, vous devez recourir à $(.)ou de manière plus équivalente $(?:.).
Brad Gilbert
Dans la syntaxe POSIX BRE, $.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.
phils
8

Que diriez-vous $^ou peut (?!)- être ? 

Bob
la source
3
Un saut de ligne correspondra à cette expression dans le mode où ^correspond le début et $la fin d'une ligne.
Gumbo
4
Peut-être qu'il voulait dire (?!)- une recherche négative pour une chaîne vide. Mais certaines versions de regex traiteront également cela comme une erreur de syntaxe.
Alan Moore
1
Une chaîne vide correspond à la première, du moins en JavaScript.
Roland Pihlakas
Dans la syntaxe POSIX BRE, $^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'
empêche de
5

Le plus rapide sera:

r = re.compile(r'a^')
r.match('whatever')

'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.

Adam Nelson
la source
En effet, (. ^) Serait environ 10% plus lent que (\ x00 ^) dans mon cas.
Peter Hansen
1
J'accepte cela, car utiliser une valeur autre que \ n car le caractère est garanti de ne jamais correspondre, et je le vois comme un peu plus lisible (étant donné que relativement peu de personnes sont des experts en regex) que l'option (?! X) x , bien que j'aie voté celui-là aussi. Dans mon cas, pour l'une ou l'autre option, j'aurais besoin d'un commentaire pour l'expliquer, donc je pense que je vais simplement ajuster ma tentative initiale à '\ x00NEVERMATCHES ^'. J'obtiens la garantie de non-correspondance de cette réponse, avec mon auto-documentation d'origine. Merci à tous pour les réponses!
Peter Hansen
3
Cela fonctionne-t-il réellement et si oui, qui a décidé de rompre avec Unix? Dans les expressions régulières Unix, ^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érale a^.
JaakkoK
Heh, c'est une bonne attaque. Je n'ai jamais testé contre cette chaîne littérale.
Adam Nelson
Oh si cela casse les expressions rationnelles Unix, alors vous allez adorer >^.
CubicleSoft
4

Python ne l'acceptera pas, mais Perl:

perl -ne 'print if /(w\1w)/'

Cette regex devrait (théoriquement) essayer de faire correspondre un nombre infini (pair) de ws, parce que le premier groupe (les ()s) revient en lui-même. Perl ne semble pas émettre d'avertissements, même sous use 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.

Chris Lutz
la source
1
La théorie est toujours agréable, mais en pratique je pense que je serais inquiet des expressions régulières dont les descriptions incluaient le mot "infini"!
Peter Hansen
perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
Brad Gilbert
@BradGilbert - Exécuter cela ici (5.10, un peu dépassé) produit "regex failed", comme l'OP l'a demandé. Cela correspond-il à votre système?
Chris Lutz
4

[^\d\D]ou (?=a)bou a$aoua^a

Bart Kiers
la source
Merci. Notez que (?! X) x était la première réponse donnée, listée ci-dessus.
Peter Hansen
Oui, il semble que j'ai scanné les autres répondeurs trop rapidement.
Bart Kiers
4

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:

var noMatch = /^[]/;

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:

try {
    var matchPattern = new RegExp(someUserInput);
}
catch (e) {
    matchPattern = noMatch;
}
indéfini
la source
4

Tous les exemples impliquant un correcteur de limites suivent la même recette. Recette:

  1. Prenez l'un des concordants de limite: ^, $, \ b, \ A, \ Z, \ z

  2. 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

^ --> .^
\A --> .\A

\ b correspond à une limite de mot donc utilisez-le entre

\b --> .\b.

$, \ Z et \ z sont destinés à la fin donc ne les utilisez pas à la fin

$ --> $.
\Z --> \Z.
\z --> \z.

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

(?=x)[^x]
(?!x)x

Si vous donnez un regard positif ou négatif en arrière après quelque chose de contraire

[^x](?<=x)
x(?<!x)

Leur pourrait être plus un tel modèle et plus de telles analogies.

Arun
la source
3

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.

  1. Entrée: chaînes ascii pseudo-aléatoires (25000 lignes différentes, longueur 8-16):

Vitesse Regex:

Total for   \A(?!x)x: 69.675450 s, 1435225 lines/s
Total for       a\bc: 71.164469 s, 1405195 lines/s
Total for    (?>a+)a: 71.218324 s, 1404133 lines/s
Total for       a++a: 71.331362 s, 1401907 lines/s
Total for         $a: 72.567302 s, 1378031 lines/s
Total for     (?=a)b: 72.842308 s, 1372828 lines/s
Total for     (?!x)x: 72.948911 s, 1370822 lines/s
Total for       ^\b$: 79.417197 s, 1259173 lines/s
Total for         $.: 88.727839 s, 1127041 lines/s
Total for       (?!): 111.272815 s, 898692 lines/s
Total for         .^: 115.298849 s, 867311 lines/s
Total for    (*FAIL): 350.409864 s, 285380 lines/s
  1. Entrée: / usr / share / dict / words (100 000 mots anglais).

Vitesse Regex:

Total for   \A(?!x)x: 128.336729 s, 1564805 lines/s
Total for     (?!x)x: 132.138544 s, 1519783 lines/s
Total for       a++a: 133.144501 s, 1508301 lines/s
Total for    (?>a+)a: 133.394062 s, 1505479 lines/s
Total for       a\bc: 134.643127 s, 1491513 lines/s
Total for     (?=a)b: 137.877110 s, 1456528 lines/s
Total for         $a: 152.215523 s, 1319326 lines/s
Total for       ^\b$: 153.727954 s, 1306346 lines/s
Total for         $.: 170.780654 s, 1175906 lines/s
Total for       (?!): 209.800379 s, 957205 lines/s
Total for         .^: 217.943800 s, 921439 lines/s
Total for    (*FAIL): 661.598302 s, 303540 lines/s

(Ubuntu sur Intel i5-3320M, noyau Linux 4.13, Perl 5.26)

filiprem
la source
Voici une comparaison JavaScript de certaines méthodes abordées ici: jsperf.com/regex-that-never-matches
thdoan
2

je crois que

\Z RE FAILS! \A

couvre même les cas où l'expression régulière comprend des indicateurs comme MULTILINE, DOTALL etc.

>>> import re
>>> x=re.compile(r"\Z RE FAILS! \A")
>>> x.match('')
>>> x.match(' RE FAILS! ')
>>>

Je crois (mais je ne l'ai pas comparé) que quelle que soit la longueur (> 0) de la chaîne entre \Zet \A, le temps de défaillance doit être constant.

tzot
la source
2
(*FAIL)

ou

(*F)

Avec PCRE et PERL, vous pouvez utiliser ce verbe de contrôle de retour arrière qui force le modèle à échouer immédiatement.

Casimir et Hippolyte
la source
2

Après avoir vu certaines de ces bonnes réponses, le commentaire de @ arantius (concernant le timing $xvs x^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 avec aau lieu de x.

In [1]: import re

In [2]: with open('/tmp/longfile.txt') as f:
   ...:     longfile = f.read()
   ...:     

In [3]: len(re.findall('\n',longfile))
Out[3]: 275000

In [4]: len(longfile)
Out[4]: 24733175

In [5]: for regex in ('x^','.^','$x','$.','$x^','$.^','$^','(?!x)x','(?!)','(?=x)y','(?=x)(?!x)',r'x\by',r'x\bx',r'^\b$'
    ...: ,r'\B\b',r'\ZNEVERMATCH\A',r'\Z\A'):
    ...:     print('-'*72)
    ...:     print(regex)
    ...:     %timeit re.search(regex,longfile)
    ...:     
------------------------------------------------------------------------
x^
6.98 ms ± 58.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
.^
155 ms ± 960 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x
111 ms ± 2.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.
111 ms ± 1.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x^
112 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.^
113 ms ± 1.44 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$^
111 ms ± 839 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?!x)x
257 ms ± 5.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?!)
203 ms ± 1.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?=x)y
204 ms ± 4.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?=x)(?!x)
210 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
x\by
7.41 ms ± 122 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
x\bx
7.42 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
^\b$
108 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\B\b
387 ms ± 5.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
\ZNEVERMATCH\A
112 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\Z\A
112 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

La première fois que j'ai exécuté ceci, j'ai oublié de raw 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.

In [6]: for regex in ('x\by','x\bx','^\b$','\B\b'):
    ...:     print('-'*72)
    ...:     print(regex, repr(regex))
    ...:     %timeit re.search(regex,longfile)
    ...:     print(re.search(regex,longfile))
    ...:     
------------------------------------------------------------------------
y 'x\x08y'
5.32 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
x 'x\x08x'
5.34 ms ± 66.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
$ '^\x08$'
122 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
None
------------------------------------------------------------------------
\ '\\B\x08'
300 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
None

Mon fichier de test a été créé en utilisant une formule pour "... Contenu lisible et aucune ligne en double" (sur Ubuntu 16.04):

$ ruby -e 'a=STDIN.readlines;275000.times do;b=[];rand(20).times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > /tmp/longfile.txt

$ head -n5 /tmp/longfile.txt 
unavailable speedometer's garbling Zambia subcontracted fullbacks Belmont mantra's
pizzicatos carotids bitch Hernandez renovate leopard Knuth coarsen
Ramada flu occupies drippings peaces siroccos Bartók upside twiggier configurable perpetuates tapering pint paralyzed
vibraphone stoppered weirdest dispute clergy's getup perusal fork
nighties resurgence chafe
nivk
la source
\B\best 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\bplutôt l' analyse comparative .
phils
2

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:

temps infini
la source
1

Peut être ça?

/$.+^/
Dan Breen
la source
En Python, cette approche ne fonctionne que si vous contrôlez les indicateurs : 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.
Alex Martelli
Mon mauvais - mélangé le $et ^.
Chris Lutz
1
Cela peut être une tentative de rechercher la fin d'une chaîne avant le début, mais j'ai constaté que $ ne signifie pas `` fin de chaîne '' à moins que ce ne soit le dernier caractère de l'expression régulière, et je m'attends à ce qu'un comportement similaire s'applique to ^, donc cela pourrait correspondre à une sous-chaîne commençant par un littéral $ et se terminant par un littéral ^
pavium
@pavium, il ne se comporte certainement pas de cette façon en Python ou Javascript. À moins que vous ne les échappiez avec \ ou que vous ne les inclassiez dans un jeu de caractères avec [], les caractères spéciaux comme $ et ^ ne devraient pas être traités comme des littéraux. Dans quelle langue avez-vous observé cela?
Peter Hansen
En Perl, au moins, cela devrait être écrit /\z.+\A/(voir perldoc perlre ). Cela empêche le mode multiligne et simple ligne ( use re '/ms') de l'affecter.
Brad Gilbert
0
'[^0-9a-zA-Z...]*'

et remplacez ... par tous les symboles imprimables;). C'est pour un fichier texte.

Drakosha
la source
Je pense qu'il doit y avoir un moyen plus court pour cela, mais c'était aussi ma première pensée ^^
FP
4
Cela correspondra à la chaîne vide. Pour capturer tous les caractères possibles, utilisez [^\x00-\xFF]+(pour les implémentations basées sur l'octet).
Ferdinand Beyer
6
Une meilleure expression serait [^\s\S]. Mais comme Ferdinand Beyer l'a déjà dit, cela correspondrait à une chaîne vide.
Gumbo
3
L'expression régulière de Drakosha peut correspondre à une chaîne vide à cause du *; 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.
Alan Moore
0

Qu'en est-il au lieu de regex, utilisez simplement une instruction if toujours fausse? En javascript:

var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}
Graviton
la source
J'ai ajouté un commentaire en réponse à la question de Charlie, expliquant pourquoi ce genre d'approche n'est pas souhaitable. En bref, j'ai besoin d'un groupe dans une regex qui sera toujours utilisé, mais dans certains cas, le groupe doit être construit pour s'assurer qu'il ne peut jamais correspondre.
Peter Hansen
-2

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:

cat /dev/urandom | hexdump | head -20
0000000 5d5d 3607 40d8 d7ab ce72 aae1 4eb3 ae47
0000010 c5e2 b9e8 910d a2d9 2eb3 fdff 6301 c85f
0000020 35d4 c282 e439 33d8 1c73 ca78 1e4d a569
0000030 8aca eb3c cbe4 aff7 d079 ca38 8831 15a5
0000040 818b 323f 0b02 caec f17f 387b 3995 88da
0000050 7b02 c80b 2d42 8087 9758 f56f b71f 0053
0000060 1501 35c9 0965 2c6e 03fe 7c6d f0ca e547
0000070 aba0 d5b6 c1d9 9bb2 fcd1 5ec7 ee9d 9963
0000080 6f0a 2c91 39c2 3587 c060 faa7 4ea4 1efd
0000090 6738 1a4c 3037 ed28 f62f 20fa 3d57 3cc0
00000a0 34f0 4bc2 3067 a1f7 9a87 086b 2876 1072
00000b0 d9e1 6b8f 5432 a60e f0f5 00b5 d9ef ed6f
00000c0 4a85 70ee 5ec4 a378 7786 927f f126 2ec2
00000d0 18c5 46fe b167 1ae6 c87c 1497 48c9 3c09
00000e0 8d09 e945 13ce 7da2 08af 1a96 c24c c022
00000f0 b051 98b3 2bf5 4d7d 5ec4 e016 a50d 355b
0000100 0e89 d9dd b153 9f0e 9a42 a51f 2d46 2435
0000110 ef35 17c2 d2aa 3cc7 e2c3 e711 d229 f108
0000120 324e 5d6a 650a d151 bc55 963f 41d3 66ee
0000130 1d8c 1fb1 1137 29b2 abf7 3af7 51fe 3cf4

Bien sûr, ce n'est pas un défi intellectuel, mais plutôt une programmation de ruban adhésif .

Hlovdal
la source
-6
new Regex(Guid.NewGuid().ToString())

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).

finnw
la source
2
"Statistiquement impossible"? Hein? Selon la façon dont le GUID est calculé, il est possible et souvent assez simple de prédire les prochains GUID (car ils dépendent de la machine qui les calcule et du temps). Vous voulez dire «improbable», «avec une très faible probabilité», mais vous ne pouvez pas dire «impossible» même pour des chaînes parfaitement aléatoires. Votre Regex correspondra à un nombre infini de chaînes - cette question recherche celle qui ne correspond à rien. Déjà.
Ferdinand Beyer