Una expresión regular que nunca será igualada por nada

131

Esto puede sonar como una pregunta estúpida, pero tuve una larga conversación con algunos de mis colegas desarrolladores y sonó como algo divertido de pensar.

Entonces; ¿Cuál es su pensamiento? ¿Cómo se ve un Regex, que nunca será igualado por ninguna cadena, nunca!

Editar : ¿Por qué quiero esto? Bueno, en primer lugar porque me parece interesante pensar en esa expresión y en segundo lugar porque lo necesito para un guión.

En ese script defino un diccionario como Dictionary<string, Regex>. Esto contiene, como puede ver, una cadena y una expresión.

Basado en ese diccionario, creo métodos que todos usan este diccionario como referencia solamente sobre cómo deben hacer su trabajo, uno de ellos compara las expresiones regulares contra un archivo de registro analizado.

Si una expresión coincide, a otra Dictionary<string, long>se le agrega un valor que devuelve la expresión. Entonces, para capturar cualquier mensaje de registro que no coincida con una expresión en el diccionario, creé un nuevo grupo llamado "desconocido".

A este grupo se agrega todo lo que no coincide con nada más. Pero para evitar que la expresión "desconocida" no coincida (por accidente) con un mensaje de registro, tuve que crear una expresión que ciertamente nunca coincide, sin importar la cadena que le dé.

Por lo tanto, ahí tienes mi razón para esta "no es una pregunta real" ...

Florian Peschka
fuente
1
Tenga en cuenta que es muy difícil demostrar que es negativo.
Lasse V. Karlsen
55
Interesante. ¿Dónde usarías una expresión regular?
Charlie Sales
1
Anotaré aquí para el registro que muchos de los comentarios anteriores y las respuestas a esta pregunta fueron originalmente de stackoverflow.com/questions/1845078/…, que es uno que pregunté. Marc Gravell los fusionó, lo que creo que hace que muchas de estas respuestas sean algo extrañas sin el contexto original preciso, hasta el punto de que algunos comentarios no parecen tener sentido. (Probablemente también elimina posibles puntos de representación futuros). Sugeriría que las preguntas con antecedentes tan detallados nunca podrían ser "duplicados exactos". Lo que sea ...
Peter Hansen
2
Esta pregunta se ha agregado a las Preguntas frecuentes sobre Expresiones regulares de desbordamiento de pila , en "Regex-Fu avanzado".
aliteralmind
3
"Tenga en cuenta que es muy difícil demostrar que es negativo". Esto se cree ampliamente, pero es completamente falso y obviamente falso ... como hemos sabido al menos desde que Euclides demostró que no hay mejor prima. Y cualquier prueba de P es una prueba de la negación de (no P). Lo que es cierto es que es difícil demostrar un empírico universal, positivo o negativo, por ejemplo, "todos los cuervos son negros" o "ningún cuervo es blanco". Los algoritmos son analíticos, no empíricos, por lo que esta es una aplicación errónea particularmente mala de la regla falsa. por ejemplo, una prueba de que el patrón 'a' no coincide con ninguna cadena que comience con 'b' no es "muy difícil".
Jim Balter

Respuestas:

66

En realidad, esto es bastante simple, aunque depende de la implementación / flags *:

$a

Coincidirá con un personaje adespués del final de la cadena. Buena suerte.

ADVERTENCIA:
Esta expresión es costosa: escaneará toda la línea, buscará el ancla de fin de línea y solo entonces no encontrará la ay devolverá una coincidencia negativa. (Vea el comentario a continuación para obtener más detalles).


* Originalmente no pensé mucho en expresiones regulares en modo multilínea, donde $también coincide con el final de una línea. De hecho, coincidiría con la cadena vacía justo antes de la nueva línea , por lo que un carácter ordinario como anunca puede aparecer después $.

Ferdinand Beyer
fuente
50
Esta expresión es costosa: escaneará toda la línea, buscará el ancla de fin de línea y solo entonces no encontrará la "a" y devolverá una coincidencia negativa. Veo que tarda ~ 480 ms en escanear un archivo de ~ 275k líneas. El inverso "a ^" toma aproximadamente el mismo tiempo, incluso si parece más eficiente. Por otro lado, una búsqueda anticipada negativa no necesita escanear nada: "(?! X) x" (cualquier cosa que no esté seguida por una x también seguida por una x, es decir, nada) toma alrededor de 30 ms, o menos del 7% del tiempo. (Medido con tiempo de GNU y egrep.)
arantius
1
En Perl eso coincidirá con el valor actual de $a. Su equivalente en Perl $(?:a)también es muy lento perl -Mre=debug -e'$_=a x 50; /$(?:a)/'.
Brad Gilbert el
@arantius, mira mi respuesta con respecto al tiempo , ya que encontré exactamente lo contrario medido con timeity python3.
nivk
No es sorprendente que seis años y una versión principal de Python pueda cambiar las cosas.
arantius
1
En la sintaxis POSIX BRE, $acoincidirá con el texto literal $a, porque $no es válido como un ancla en ese patrón.
PHILS
76

Apalancamiento negative lookahead:

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

este RE es una contradicción en los términos y, por lo tanto, nunca coincidirá con nada.

NOTA:
En Python, re.match () agrega implícitamente un ancla de inicio de cadena ( \A) al comienzo de la expresión regular. Este ancla es importante para el rendimiento: sin él, se escaneará toda la cadena. Aquellos que no usan Python querrán agregar el ancla explícitamente:

\A(?!x)x
Alex Martelli
fuente
@Chris, sí, también, (?=x)(?!x)y así sucesivamente (concatenaciones de miradas contradictorias, y lo mismo para las miradas hacia atrás), y muchas de ellas también funcionan para valores arbitrarios de x(las miradas hacia atrás necesitan xs que coincidan con cadenas de longitud fija).
Alex Martelli el
1
Parece funcionar bien. Pero, ¿qué pasa con solo (?!) En su lugar? Como () siempre coincidirá, ¿no se garantizará (?!) Que nunca coincidirá?
Peter Hansen el
2
@ Peter, sí, si Python acepta esa sintaxis (y las versiones recientes parecen serlo), entonces también sería contradictorio. Otra idea (no tan elegante, pero cuantas más ideas tenga, más r'a\bc'probabilidades tendrá de encontrar una que funcione en todos los motores RE de interés): buscar un límite de palabras inmediatamente rodeado de letras en ambos lados (variante: caracteres sin palabras en ambos lados).
Alex Martelli el
1
Curiosamente, mi original con un literal simple que "sé" que no aparecerá en mi entrada resulta ser el más rápido, en Python. Con una cadena de entrada de 5 MB, y al usar esto en una operación sub (), (?! X) x tarda un 21% más, (?! ()) Es un 16% y ($ ^) un 6% más. Puede ser significativo en algunos casos, aunque no en el mío.
Peter Hansen el
2
Eso puede ser bastante lento perl -Mre=debug -e'$_=x x 8; /(?!x)x/'. Puede hacerlo más rápido al anclarlo al principio \A(?!x)xo al final (?!x)x\z. perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Brad Gilbert
43

Uno que se perdió:

^\b$

No puede coincidir porque la cadena vacía no contiene un límite de palabra. Probado en Python 2.5.

Mark Byers
fuente
77
Esta es la mejor respuesta. No usa lookaheads, no se rompe en algunas implementaciones de expresiones regulares, no usa un carácter específico (por ejemplo, 'a') y falla en un máximo de 3 pasos de procesamiento (de acuerdo con regex101.com) sin escanear todo cadena de entrada Esto también es fácil de entender de un vistazo.
CubicleSoft
1
Esto realmente falla en Emacs en ciertas condiciones (si hay una línea en blanco al comienzo o al final del búfer), sin embargo \`\b\'funciona, lo que sustituye la sintaxis de Emacs por "principio / fin de texto" (en lugar de "principio / fin" desconectado").
PHILS
35

mira alrededor:

(?=a)b

Para los novatos de expresiones regulares: la mirada positiva hacia adelante (?=a)asegura que el siguiente carácter sea a, pero no cambia la ubicación de búsqueda (ni incluye la 'a' en la cadena coincidente). Ahora que se confirma que el siguiente carácter es a, la parte restante de la expresión regular ( b) coincide solo si el siguiente carácter lo es b. Por lo tanto, esta expresión regular coincide solo si un personaje es ambos ay bal mismo tiempo.

Amarghosh
fuente
30

a\bc, donde \bes una expresión de ancho cero que coincide con el límite de la palabra.

No puede aparecer en el medio de una palabra, a lo que lo forzamos.

P Shved
fuente
Si su caso de uso le permite anclar el patrón al comienzo de la cadena, entonces esa mejora evitará que el motor regexp busque y pruebe cada instancia de una aen el texto.
PHILS
20

$.

.^

$.^

(?!)

Knio
fuente
1
¡Lindo! Mi subconsciente me alejó de ideas como las tres primeras, ya que son "ilegales" ... conceptualmente, pero obviamente no a la expresión regular. No reconozco el (!) Uno ... tendrá que buscarlo.
Peter Hansen el
1
Bien entonces, me gusta la respuesta (?!) ... efectivamente lo que sugirió Alex. Tenga en cuenta que en stackoverflow.com/questions/1723182 (señalado por Amarghosh arriba) alguien afirma que "algunos sabores" de expresiones regulares considerarían que un error de sintaxis. Python le gusta bien sin embargo. Tenga en cuenta que sus otras sugerencias fallarían con los modos re.DOTALL | re.MULTILINE en Python.
Peter Hansen el
1
¿Esto ha sido probado? Supongo que ^solo tiene un significado especial como primer carácter de una $expresión regular , y solo tiene un significado especial al final de una expresión regular, a menos que la expresión regular sea una expresión de varias líneas.
PP.
En realidad, en Perl /$./significa algo completamente diferente. Significa hacer coincidir el valor actual de $.(número de línea de entrada) . Incluso /$(.)/podría coincidir con algo si escribiste use re '/s';antes. ( perl -E'say "\n" =~ /$(.)/s || 0')
Brad Gilbert el
En la sintaxis POSIX BRE, ^y $sólo son especiales al principio y al final (respectivamente) del patrón, por lo que ninguno de $.o .^o $.^funcionaría. (?!)es una característica de Perl / PCRE, creo.
phils
13

Máxima correspondencia

a++a

Al menos uno aseguido de cualquier número de a's, sin retroceder. Luego trata de hacer coincidir uno más a.

o Subexpresión independiente

Esto es equivalente a poner a+una subexpresión independiente, seguida de otra a.

(?>a+)a
Brad Gilbert
fuente
10

Perl 5.10 admite palabras de control especiales llamadas "verbos", que están encerrados en (*...)secuencia. (Compárese con (?...)una secuencia especial). Entre ellos, incluye el (*FAIL)verbo que regresa de la expresión regular inmediatamente.

Tenga en cuenta que los verbos también se implementan en PCRE poco después, por lo que puede usarlos en PHP u otros lenguajes usando la biblioteca PCRE también. (Sin embargo, no puedes en Python o Ruby. Usan su propio motor).

Kang Seonghoon
fuente
Los documentos para eso en perldoc.perl.org/perlre.html#%28%2AFAIL%29-%28%2AF%29 dicen "Este patrón no coincide con nada y siempre falla. Es equivalente a (?!), Pero más fácil de leer. De hecho, (?!) se optimiza internamente en (* FAIL) ". Interesante, ya que (?!) Es mi respuesta "pura" favorita hasta ahora (aunque no funciona en Javascript). Gracias.
Peter Hansen el
10
\B\b

\bcoincide con los límites de las palabras: la posición entre una letra y una no letra (o el límite de la cadena).
\Bes su complemento: coincide con la posición entre dos letras o entre no letras.

Juntos no pueden igualar ninguna posición.

Ver también:

Kobi
fuente
Esto parece una excelente solución, siempre que esté anclado a un punto específico (el comienzo del texto parecería sensato). Si no lo hace, entonces es una solución terrible , porque cada límite que no sea de palabra en el texto se probará para ver si es seguido por un límite de palabra. Entonces la versión sensata sería algo así ^\B\b. En los idiomas en los que "comienzo de texto" y "comienzo de línea" tienen una sintaxis diferente, querrá usar la sintaxis "comienzo de texto", de lo contrario, probará cada línea. (por ejemplo, en Emacs esto sería \`\B\bo "\\`\\B\\b".)
phils
Dicho esto, ahora he notado que el propósito declarado de esta pregunta es obtener una expresión regular para usar en un grupo, en cuyo caso ^es problemático en cierta sintaxis de expresión regular (por ejemplo, POSIX BRE) donde ^solo hay un ancla cuando es el primer carácter del patrón, y de lo contrario coincide con un ^carácter literal .
PHILS
@phils - Creo que lo estás pensando demasiado :)- esta es una pregunta no práctica, donde el objetivo era encontrar una respuesta interesante, no una respuesta eficiente. Dicho esto, el patrón se puede rechazar en el tiempo de línea (con el tamaño de la cadena de destino), por lo que no es malo para una expresión regular: la mayoría de los patrones aquí son iguales, e incluso ^podrían ser lineales si no están optimizados.
Kobi
Re: optimizaciones, estoy dispuesto a ignorar un motor de expresiones regulares que espera encontrar "el comienzo del texto" en cualquier otra posición :)
phils
Además, no es una pregunta y respuesta tan poco práctica: la única razón por la que terminé aquí fue para ver si alguien podía sugerir una solución más eficiente para mí con el propósito práctico de configurar una variable Emacs particular que requiriera un valor de expresión regular, pero que yo quería deshabilitar efectivamente.
PHILS
8

Esto parece funcionar:

$.
Jerry Fernholz
fuente
2
Eso es similar al ejemplo de Ferdinand Beyer.
Gumbo
9
Y coincidirá en modo punto-coincidencias-líneas nuevas.
Tim Pietzcker
En Perl, eso realmente coincidirá con el número de línea de entrada actual $.. En ese caso, debe recurrir $(.)ao más equivalente $(?:.).
Brad Gilbert el
En la sintaxis POSIX BRE, $.coincidirá con un literal $seguido de cualquier carácter, porque $no es válido como un ancla en ese patrón.
PHILS
8

¿Qué $^tal o tal vez (?!)

Bob
fuente
3
Un salto de línea coincidirá con esta expresión en el modo donde ^coincide con el inicio y $el final de una línea.
Gumbo
44
Tal vez quiso decir (?!): una anticipación negativa para una cadena vacía. Pero algunos sabores de expresiones regulares también lo tratarán como un error de sintaxis.
Alan Moore
1
Una cadena vacía coincide con la primera, al menos en JavaScript.
Roland Pihlakas
En la sintaxis POSIX BRE, $^coincidirá con esos caracteres literales, porque los caracteres no son válidos como anclas (es decir, la razón por la que usó el patrón hace que no haga lo que deseaba)
phils
5

El más rápido será:

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

'a' puede ser cualquier carácter no especial ('x', 'y'). La implementación de Knio podría ser un poco más pura, pero esta será más rápida para todas las cadenas que no comiencen con el carácter que elija en lugar de 'a' porque no coincidirá después del primer carácter en lugar de después del segundo en esos casos.

Adam Nelson
fuente
De hecho, (. ^) Sería aproximadamente un 10% más lento que (\ x00 ^) en mi caso.
Peter Hansen el
1
Estoy aceptando esto, ya que el uso de cualquier valor que no sea \ n ya que el personaje nunca coincidirá, y lo veo un poco más legible (dado que relativamente pocas personas son expertos en expresiones regulares) que la opción (?! X) x , aunque también voté por eso. En mi caso, para cualquier opción necesitaría un comentario para explicarlo, así que creo que simplemente ajustaré mi intento original de '\ x00NEVERMATCHES ^'. Recibo la garantía de no coincidencia de esta respuesta, con mi autodocumentación original. Gracias a todos por las respuestas!
Peter Hansen
3
¿Esto realmente funciona y, de ser así, quién decidió romper con Unix? En Unix regexps, ^es especial solo como primer personaje y de manera similar con $. Con cualquier herramienta Unix, esa expresión regular coincidirá con cualquier cosa que contenga la cadena literal a^.
JaakkoK
Je, ese es un buen ataque. Nunca probé contra esa cadena literal.
Adam Nelson el
Oh, si eso rompe las expresiones regulares de Unix, entonces te encantará >^.
CubicleSoft
4

Python no lo aceptará, pero Perl:

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

Esta expresión regular debería (en teoría) tratar de hacer coincidir un número infinito (par) de ws, porque el primer grupo ( ()s) se repite en sí mismo. Perl no parece emitir ninguna advertencia, incluso debajo use strict; use warnings;, por lo que supongo que es al menos válido, y mis pruebas (mínimas) no coinciden con nada, así que lo envío para su crítica.

Chris Lutz
fuente
1
La teoría siempre es agradable, pero en la práctica creo que me preocuparían las expresiones regulares cuyas descripciones incluyen la palabra "infinito".
Peter Hansen el
perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
Brad Gilbert el
@BradGilbert: ejecutar eso aquí (5.10, un poco desactualizado) produce un "regex fallido", como solicitó el OP. ¿Coincide con su sistema?
Chris Lutz
4

[^\d\D]o (?=a)bo a$aoa^a

Bart Kiers
fuente
Gracias. Tenga en cuenta que (?! X) x fue la primera respuesta dada, enumerada anteriormente.
Peter Hansen
Sí, parecía que escaneé los otros respondedores demasiado rápido.
Bart Kiers
4

Esto no funcionará para Python y muchos otros lenguajes, pero en una expresión regular de Javascript, []es una clase de caracteres válida que no se puede comparar. Entonces, lo siguiente debería fallar inmediatamente, sin importar la entrada:

var noMatch = /^[]/;

Me gusta más que /$a/porque, para mí, comunica claramente su intención. Y en cuanto a cuándo lo necesitaría, lo necesitaba porque necesitaba un respaldo para un patrón compilado dinámicamente basado en la entrada del usuario. Cuando el patrón no es válido, necesito reemplazarlo con un patrón que no coincida con nada. Simplificado, se ve así:

try {
    var matchPattern = new RegExp(someUserInput);
}
catch (e) {
    matchPattern = noMatch;
}
indefinido
fuente
4

Todos los ejemplos que involucran una coincidencia de límites siguen la misma receta. Receta:

  1. Tome cualquiera de los comparadores de límites: ^, $, \ b, \ A, \ Z, \ z

  2. Hacer lo contrario a lo que están destinados

Ejemplos:

^ y \ A están destinados al principio, así que no los use al principio

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

\ b coincide con un límite de palabra, así que úselo entre

\b --> .\b.

$, \ Z y \ z están destinados al final, así que no los uses al final

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

Otros implican el uso de lookahead y lookbehind, que también funcionan con la misma analogía: si da un lookahead positivo o negativo seguido de algo opuesto

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

Si das una mirada positiva o negativa detrás de algo opuesto

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

Podrían existir más patrones y más analogías.

Arun
fuente
3

¡Tantas buenas respuestas!

Similar a la respuesta de @ nivk, me gustaría compartir la comparación de rendimiento de Perl para diferentes variantes de expresiones regulares que nunca coinciden.

  1. Entrada: cadenas ascii pseudoaleatorias (25,000 líneas diferentes, longitud 8-16):

Velocidad de expresión regular:

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. Entrada: / usr / share / dict / words (100,000 palabras en inglés).

Velocidad de expresión regular:

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 en Intel i5-3320M, Linux kernel 4.13, Perl 5.26)

filiprem
fuente
Aquí hay una comparación de JavaScript de algunos métodos cubiertos aquí: jsperf.com/regex-that-never-matches
thdoan
2

Yo creo eso

\Z RE FAILS! \A

cubre incluso los casos en los que la expresión regular incluye marcas como MULTILINE, DOTALL, etc.

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

Creo (pero no lo he comparado) que cualquiera que sea la longitud (> 0) de la cadena entre \Zy \A, el tiempo de falla debe ser constante.

tzot
fuente
2
(*FAIL)

o

(*F)

Con PCRE y PERL puede usar este verbo de control de retroceso que obliga al patrón a fallar inmediatamente.

Casimir et Hippolyte
fuente
2

Después de ver algunas de estas excelentes respuestas, el comentario de @arantius (con respecto al tiempo $xvs x^vs (?!x)x) sobre la respuesta actualmente aceptada me hizo querer cronometrar algunas de las soluciones dadas hasta ahora.

Usando el estándar de línea de 275k de @ arantius, ejecuté las siguientes pruebas en Python (v3.5.2, IPython 6.2.1).

TL; DR: 'x^'y 'x\by'son los más rápidos por un factor de al menos ~ 16, y contrario al hallazgo de @ arantius, (?!x)xfue uno de los más lentos (~ 37 veces más lento). Entonces, la cuestión de la velocidad ciertamente depende de la implementación. Pruébelo usted mismo en su sistema previsto antes de confirmar si la velocidad es importante para usted.

ACTUALIZACIÓN: Al parecer, existe una gran discrepancia entre el tiempo 'x^'y 'a^'. Consulte esta pregunta para obtener más información y la edición anterior para los tiempos más lentos con en alugar 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 primera vez que ejecuté esto, olvidé rmostrar las últimas 3 expresiones, por lo que '\b'se interpretó como '\x08'el carácter de retroceso. Sin embargo, para mi sorpresa, ¡ 'a\x08c'fue más rápido que el resultado más rápido anterior! Para ser justos, aún coincidirá con ese texto, pero pensé que todavía valía la pena señalarlo porque no estoy seguro de por qué es más rápido.

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

Mi archivo de prueba fue creado usando una fórmula para "... Contenido legible y sin líneas duplicadas" (en 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
revs nivk
fuente
\B\btiene un rendimiento terriblemente defectuoso (como todos los patrones que no están anclados a una posición, pero este patrón es particularmente malo). Intenta hacer benchmarking en su ^\B\blugar.
PHILS
2

Expresiones regulares vacías

La mejor expresión regular para que nunca coincida con nada es una expresión regular vacía. Pero no estoy seguro de que todo el motor de expresiones regulares lo acepte.

Regex imposible

La otra solución es crear una expresión regular imposible. Descubrí que $-^solo toma dos pasos para calcular, independientemente del tamaño de su texto ( https://regex101.com/r/yjcs1Z/1 ).

Para referencia:

  • $^y $.tome 36 pasos para calcular -> O (1)
  • \b\B toma 1507 pasos en mi muestra y aumenta con el número de caracteres en su cadena -> O (n)

Tema más popular sobre esta pregunta:

Eón
fuente
1

¿Tal vez esto?

/$.+^/
Dan Breen
fuente
En Python, este enfoque solo funciona si controla las banderas : re.compile('$.+^', re.MULTILINE|re.DOTALL).search('a\nb\nc\n')devuelve un objeto de coincidencia correspondiente a byc (y todas las líneas nuevas adyacentes y entre ellas). El enfoque de anticipación negativa que recomiendo funciona (es decir, no coincide con nada) para cualquier combinación de indicadores con los que podría compilarse.
Alex Martelli el
Mi mal - mezclado el $y ^.
Chris Lutz el
1
Esto puede ser un intento de buscar el final de una cadena antes del comienzo, pero he descubierto que $ no significa 'final de cadena' a menos que sea el último carácter de la expresión regular, y espero que se aplique un comportamiento similar ^, por lo que esto podría coincidir con una subcadena que comienza con un $ literal y termina con un literal ^
pavium el
@pavium, ciertamente no se comporta de esa manera en Python o Javascript. A menos que los escape con \ o los incluya en un conjunto de caracteres con [], los caracteres especiales como $ y ^ no deben tratarse como literales. ¿En qué idioma observaste esto?
Peter Hansen el
En Perl, al menos, eso debería escribirse /\z.+\A/(ver perldoc perlre ). Eso evita que el modo de varias líneas y una sola línea ( use re '/ms') lo afecte.
Brad Gilbert el
0
'[^0-9a-zA-Z...]*'

y reemplace ... con todos los símbolos imprimibles;). Eso es para un archivo de texto.

Drakosha
fuente
Creo que tiene que haber un camino más corto para eso, pero ese fue mi primer pensamiento también ^^
FP
44
Esto coincidirá con la cadena vacía. Para capturar todos los caracteres posibles, use [^\x00-\xFF]+(para implementaciones basadas en bytes).
Ferdinand Beyer
66
Una mejor expresión sería [^\s\S]. Pero como ya dijo Ferdinand Beyer, coincidiría con una cadena vacía.
Gumbo
3
La expresión regular de Drakosha puede coincidir con una cadena vacía debido a *; déjalo apagado o reemplázalo con +, y tiene que coincidir con al menos un personaje. Si la clase excluye todos los caracteres posibles, no puede coincidir con nada.
Alan Moore
0

¿Qué pasa en lugar de expresiones regulares, solo use una declaración if falsa? En javascript:

var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}
Graviton
fuente
Agregué un comentario en respuesta a la pregunta de Charlie, explicando por qué este tipo de enfoque no es deseable. En resumen, necesito un grupo dentro de una expresión regular que siempre se utilizará, pero en algunos casos el grupo debe estar construido para garantizar que nunca coincida.
Peter Hansen el
-2

Una solución portátil que no dependerá de la implementación de regexp es usar una cadena constante que está seguro de que nunca aparecerá en los mensajes de registro. Por ejemplo, haga una cadena basada en lo siguiente:

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

Claro, este no es un desafío intelectual, sino más bien una programación de cinta adhesiva .

hlovdal
fuente
-6
new Regex(Guid.NewGuid().ToString())

Crea un patrón que solo contiene caracteres alfanuméricos y ' -' (ninguno de los cuales son caracteres especiales de expresiones regulares), pero es estadísticamente imposible que la misma cadena haya aparecido en algún lugar antes (porque ese es el objetivo de un GUID).

finnw
fuente
2
¿"Estadísticamente imposible"? ¿Eh? Dependiendo de cómo se calcule el GUID, es posible y, a menudo, bastante simple predecir los siguientes GUID (ya que dependen de la máquina que los computa y el tiempo). Quieres decir "improbable", "con una probabilidad muy pequeña", pero no puedes decir "imposible" incluso para cadenas perfectamente aleatorias. Su Regex coincidirá con un número infinito de cadenas: esta pregunta está buscando una que no coincida con nada. Nunca.
Ferdinand Beyer