solo simplificar regulares regular palabra online letras expresiones expresion exacta especiales espacios espacio ejemplos direccion casa caracteres blanco alfanumerico regex regex-negation regex-lookarounds regex-greedy regex-group

regex - simplificar - expresiones regulares java caracteres especiales



¿Expresión regular para hacer coincidir una línea que no contiene una palabra? (27)

Puntos de referencia

Decidí evaluar algunas de las opciones presentadas y comparar su rendimiento, así como usar algunas características nuevas. Benchmarking en .NET Regex Engine: http://regexhero.net/tester/

Texto de referencia:

Las primeras 7 líneas no deben coincidir, ya que contienen la expresión buscada, mientras que las 7 líneas inferiores deben coincidir.

Regex Hero is a real-time online Silverlight Regular Expression Tester. XRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester. RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her egex Hero egex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her is a real-time online Silverlight Regular Expression Tester. Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester. Nobody is a real-time online Silverlight Regular Expression Tester. Regex Her o egex Hero Regex Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester.

Resultados:

Los resultados son las iteraciones por segundo, ya que la mediana de 3 ejecuciones: mayor número = mejor

01: ^((?!Regex Hero).)*$ 3.914 // Accepted Answer 02: ^(?:(?!Regex Hero).)*$ 5.034 // With Non-Capturing group 03: ^(?>[^R]+|R(?!egex Hero))*$ 6.137 // Lookahead only on the right first letter 04: ^(?>(?:.*?Regex Hero)?)^.*$ 7.426 // Match the word and check if you''re still at linestart 05: ^(?(?=.*?Regex Hero)(?#fail)|.*)$ 7.371 // Logic Branch: Find Regex Hero? match nothing, else anything P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT)) ????? // Logic Branch in Perl - Quick FAIL P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ????? // Direct COMMIT & FAIL in Perl

Ya que .NET no admite los verbos de acción (* FAIL, etc.) no pude probar las soluciones P1 y P2.

Resumen:

Intenté probar la mayoría de las soluciones propuestas, algunas optimizaciones son posibles para ciertas palabras. Por ejemplo, si las dos primeras letras de la cadena de búsqueda no son las mismas, la respuesta 03 se puede expandir a ^(?>[^R]+|R+(?!egex Hero))*$ resultando en una pequeña ganancia de rendimiento.

Pero la solución más rápida y más legible en términos generales de rendimiento parece ser 05 usando una declaración condicional o 04 con el cuantificador posesivo. Creo que las soluciones de Perl deberían ser incluso más rápidas y más fáciles de leer.

Sé que es posible hacer coincidir una palabra y luego invertir las coincidencias con otras herramientas (por ejemplo, grep -v ). Sin embargo, me gustaría saber si es posible hacer coincidir las líneas que no contienen una palabra específica (por ejemplo, hede) usando una expresión regular.

Entrada:

hoho hihi haha hede

Código:

grep "<Regex for ''doesn''t contain hede''>" input

Salida deseada:

hoho hihi haha


Cómo usar los verbos de control de retroceso de PCRE para hacer coincidir una línea que no contiene una palabra

Aquí hay un método que no he visto usado antes:

/.*hede(*COMMIT)^|/

Cómo funciona

Primero, trata de encontrar "hede" en algún lugar de la línea. Si tiene éxito, en este punto, (*COMMIT)le indica al motor que no solo no retroceda en el caso de una falla, sino que tampoco intente realizar ninguna otra comparación en ese caso. Luego, tratamos de hacer coincidir algo que no puede coincidir (en este caso, ^).

Si una línea no contiene "hede", la segunda alternativa, un subpatrón vacío, coincide exitosamente con la cadena del sujeto.

Este método no es más eficiente que un lookahead negativo, pero me di cuenta de que simplemente lo pondría aquí en caso de que alguien lo encuentre ingenioso y le sirva para otras aplicaciones más interesantes.


Aquí hay una buena explicación de por qué no es fácil negar un regex arbitrario. Sin embargo, tengo que estar de acuerdo con las otras respuestas: si esto no es una pregunta hipotética, entonces una expresión regular no es la opción correcta aquí.


Así es como lo haría:

^[^h]*(h(?!ede)[^h]*)*$

Preciso y más eficiente que las otras respuestas. Implementa la técnica de eficiencia de "desenrollado del bucle" de Friedl y requiere mucho menos retroceso.


Como nadie más ha dado una respuesta directa a la pregunta que se hizo , lo haré.

La respuesta es que con POSIX grep , es imposible satisfacer literalmente esta solicitud:

grep "Regex for doesn''t contain hede" Input

La razón es que POSIX grep solo se requiere para trabajar con expresiones regulares básicas , que simplemente no son lo suficientemente potentes para realizar esa tarea (no son capaces de analizar lenguajes regulares, debido a la falta de alternancia y agrupación).

Sin embargo, GNU grep implementa extensiones que lo permiten. En particular, /| es el operador de alternancia en la implementación de BRE de GNU, y /( y /) son los operadores de agrupación. Si su motor de expresiones regulares admite alternancia, expresiones de corchetes negativos, agrupación y la estrella Kleene, y es capaz de anclar al principio y al final de la cadena, eso es todo lo que necesita para este enfoque.

Con GNU grep , sería algo como:

grep "^/([^h]/|h/(h/|eh/|edh/)*/([^eh]/|e[^dh]/|ed[^eh]/)/)*/(/|h/(h/|eh/|edh/)*/(/|e/|ed/)/)$" Input

(Encontrado con Grail y algunas optimizaciones adicionales hechas a mano).

También puede usar una herramienta que implementa expresiones regulares extendidas , como egrep , para deshacerse de las barras invertidas:

egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" Input

Aquí hay un script para probarlo (tenga en cuenta que genera un archivo testinput.txt en el directorio actual):

#!/bin/bash REGEX="^/([^h]/|h/(h/|eh/|edh/)*/([^eh]/|e[^dh]/|ed[^eh]/)/)*/(/|h/(h/|eh/|edh/)*/(/|e/|ed/)/)$" # First four lines as in OP''s testcase. cat > testinput.txt <<EOF hoho hihi haha hede h he ah head ahead ahed aheda ahede hhede hehede hedhede hehehehehehedehehe hedecidedthat EOF diff -s -u <(grep -v hede testinput.txt) <(grep "$REGEX" testinput.txt)

En mi sistema se imprime:

Files /dev/fd/63 and /dev/fd/62 are identical

como se esperaba.

Para aquellos interesados ​​en los detalles, la técnica empleada es convertir la expresión regular que coincide con la palabra en un autómata finito, luego invertir el autómata cambiando cada estado de aceptación a no aceptación y viceversa, y luego convertir el FA resultante a una expresión regular.

Finalmente, como todos han notado, si su motor de expresión regular admite lookahead negativo, eso simplifica mucho la tarea. Por ejemplo, con GNU grep:

grep -P ''^((?!hede).)*$'' Input

Actualización: Recientemente he encontrado la excelente biblioteca FormalTheory Kendall Hopkins, escrita en PHP, que proporciona una funcionalidad similar a la de Grail.Al usarlo, y un simplificador escrito por mí mismo, he podido escribir un generador en línea de expresiones regulares negativas con una frase de entrada (solo caracteres alfanuméricos y espaciales actualmente admitidos): http://www.formauri.es/personal/pgimeno/misc/non-match-regex/

Para hedeello produce:

^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$

que es equivalente a lo anterior.


Con esto, evitas probar un lookahead en cada posición:

/^(?:[^h]+|h++(?!ede))*+$/

equivalente a (para .net):

^(?>(?:[^h]+|h+(?!ede))*)$

Respuesta antigua:

/^(?>[^h]+|h+(?!ede))*$/


Con lookahead negativo, la expresión regular puede coincidir con algo que no contiene un patrón específico. Esto es respondido y explicado por Bart Kiers. Gran explicacion

Sin embargo, con la respuesta de Bart Kiers, la parte de búsqueda anticipada probará de 1 a 4 caracteres por delante al tiempo que combina cualquier carácter individual. Podemos evitar esto y dejar que la parte de búsqueda anticipada verifique todo el texto, asegurarnos de que no haya ''hede'', y luego la parte normal (. *) Puede comer todo el texto de una sola vez.

Aquí está el regex mejorado:

/^(?!.*?hede).*$/

Tenga en cuenta que el cuantificador perezoso (*?) En la parte de búsqueda anticipada negativa es opcional, puede usar el cuantificador codicioso (*) en función de sus datos: si ''hede'' está presente y en la mitad inicial del texto, el cuantificador perezoso puede se más rápido; De lo contrario, el codificador codicioso será más rápido. Sin embargo, si ''hede'' no aparece, ambos serían igual de lentos.

Aquí está el código de demostración .

Para obtener más información sobre Lookahead, consulte el excelente artículo: Mastering Lookahead and Lookbehind .

Además, consulte RegexGen.js , un generador de expresiones regulares de JavaScript que ayuda a construir expresiones regulares complejas. Con RegexGen.js, puede construir la expresión regular de una manera más legible:

var _ = regexGen; var regex = _( _.startOfLine(), _.anything().notContains( // match anything that not contains: _.anything().lazy(), ''hede'' // zero or more chars that followed by ''hede'', // i.e., anything contains ''hede'' ), _.endOfLine() );


Desde la introducción de ruby-2.4.1, podemos usar el nuevo operador ausente en las expresiones regulares de Ruby

del doc oficial

(?~abc) matches: "", "ab", "aab", "cccc", etc. It doesn''t match: "abc", "aabc", "ccccabc", etc.

Por lo tanto, en su caso ^(?~hede)$ hace el trabajo por usted

2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)} => ["hoho", "hihi", "haha"]


El OP no especificó o etiquetó la publicación para indicar el contexto (lenguaje de programación, editor, herramienta) en el que se usará Regex.

Para mí, a veces necesito hacer esto mientras Textpad un archivo usando Textpad .

Textpad compatible con algunos Regex, pero no es compatible con búsqueda anticipada ni detrás, por lo que toma unos pocos pasos.

Si estoy buscando retener todas las líneas que NO contienen la cadena hede , lo haría así:

1. Busque / reemplace todo el archivo para agregar una "Etiqueta" única al principio de cada línea que contenga cualquier texto.

Search string:^(.) Replace string:<@#-unique-#@>/1 Replace-all

2. Elimine todas las líneas que contienen la cadena hede (la cadena de reemplazo está vacía):

Search string:<@#-unique-#@>.*hede.*/n Replace string:<nothing> Replace-all

3. En este punto, todas las líneas restantes NO contienen la cadena hede . Elimine la "Etiqueta" única de todas las líneas (la cadena de reemplazo está vacía):

Search string:<@#-unique-#@> Replace string:<nothing> Replace-all

Ahora tiene eliminado el texto original con todas las líneas que contienen la cadena hede .

Si estoy buscando hacer algo más que solo líneas que NO contienen la cadena hede , lo haría así:

1. Busque / reemplace todo el archivo para agregar una "Etiqueta" única al principio de cada línea que contenga cualquier texto.

Search string:^(.) Replace string:<@#-unique-#@>/1 Replace-all

2. Para todas las líneas que contienen la cadena hede , elimine la "Etiqueta" única:

Search string:<@#-unique-#@>(.*hede) Replace string:/1 Replace-all

3. En este punto, todas las líneas que comienzan con la "Etiqueta" única, NO contienen la cadena hede . Ahora puedo hacer mi Algo Más solo para esas líneas.

4. Cuando termine, elimino la "Etiqueta" única de todas las líneas (la cadena de reemplazo está vacía):

Search string:<@#-unique-#@> Replace string:<nothing> Replace-all


FWIW, dado que los lenguajes regulares (también conocidos como lenguajes racionales) están cerrados por complementación, siempre es posible encontrar una expresión regular (también conocida como expresión racional) que niega otra expresión. Pero no hay muchas herramientas que implementen esto.

Vcsn es compatible con este operador (que denota {c} , postfix).

Primero define el tipo de sus expresiones: las etiquetas son letras ( lal_char ) para elegir de la A a la z por ejemplo (la definición del alfabeto cuando se trabaja con complementación es, por supuesto, muy importante), y el "valor" calculado para cada palabra es solo un booleano: true la palabra es aceptada, false , rechazado.

En Python:

In [5]: import vcsn c = vcsn.context(''lal_char(a-z), b'') c Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} → 𝔹

luego ingresas tu expresión:

In [6]: e = c.expression(''(hede){c}''); e Out[6]: (hede)^c

convertir esta expresión a un autómata:

In [7]: a = e.automaton(); a

Finalmente, convierte este autómata de nuevo a una expresión simple.

In [8]: print(a.expression()) /e+h(/e+e(/e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*

donde + generalmente se denota | , /e denota la palabra vacía, y [^] generalmente se escribe . (cualquier personaje). Así que, con un poco de reescritura ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).* .

Puedes ver este ejemplo , y probar Vcsn en línea there .


La noción de que las expresiones regulares no admiten la coincidencia inversa no es del todo cierta. Puedes imitar este comportamiento usando miradas negativas:

^((?!hede).)*$

La expresión regular anterior coincidirá con cualquier cadena o línea sin un salto de línea, que no contenga la (sub) cadena ''hede''. Como se mencionó, esto no es algo que la expresión regular sea "buena" en (o debería hacer), pero aún así, es posible.

Y si también necesita hacer coincidir los caracteres de salto de línea, use el modificador DOT-ALL (los s al final en el siguiente patrón):

/^((?!hede).)*$/s

o utilízalo en línea:

/(?s)^((?!hede).)*$/

(donde los /.../ son los delimitadores de expresiones regulares, es decir, no forman parte del patrón)

Si el modificador DOT-ALL no está disponible, puede imitar el mismo comportamiento con la clase de caracteres [/s/S] :

/^((?!hede)[/s/S])*$/

Explicación

Una cadena es solo una lista de n caracteres. Antes, y después de cada carácter, hay una cadena vacía. Así que una lista de n caracteres tendrá n+1 cadenas vacías. Considera la cadena "ABhedeCD" :

┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐ S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│ └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘ index 0 1 2 3 4 5 6 7

donde las e son las cuerdas vacías. El regex (?!hede). mira hacia adelante para ver si no hay una subcadena "hede" para ser vista, y si ese es el caso (entonces se ve algo más), entonces el . (punto) coincidirá con cualquier carácter, excepto un salto de línea. Las miradas también se llaman aserciones de ancho cero porque no consumen ningún carácter. Sólo afirman / validan algo.

Entonces, en mi ejemplo, cada cadena vacía se valida primero para ver si no hay "hede" adelante, antes de que un carácter sea consumido por el . (punto). El regex (?!hede). lo hará solo una vez, por lo que se envuelve en un grupo y se repite cero o más veces: ((?!hede).)* . Finalmente, el inicio y el final de la entrada están anclados para garantizar que se consuma toda la entrada: ^((?!hede).)*$

Como puede ver, la entrada "ABhedeCD" fallará porque en e3 , la expresión regular (?!hede) falla (¡hay "hede" más adelante!).


Las respuestas dadas están perfectamente bien, solo un punto académico:

Las expresiones regulares en el significado de las ciencias de la computación teóricas NO SON BÁSICAS hacerlo de esta manera. Para ellos tenía que verse algo así:

^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$)

Esto solo hace una coincidencia COMPLETA. Hacerlo para las sub-partidas sería incluso más incómodo.


Lo anterior (?:(?!hede).)* Es excelente porque se puede anclar.

^(?:(?!hede).)*$ # A line without hede foo(?:(?!hede).)*bar # foo followed by bar, without hede between them

Pero lo siguiente sería suficiente en este caso:

^(?!.*hede) # A line without hede

Esta simplificación está lista para agregar cláusulas "AND":

^(?!.*hede)(?=.*foo)(?=.*bar) # A line with foo and bar, but without hede ^(?!.*hede)(?=.*foo).*bar # Same


No es una expresión regular, pero me parece lógico y útil usar vástagos en serie con tuberías para eliminar el ruido.

p.ej. buscar un archivo de configuración de apache sin todos los comentarios-

grep -v ''/#'' /opt/lampp/etc/httpd.conf # this gives all the non-comment lines

y

grep -v ''/#'' /opt/lampp/etc/httpd.conf | grep -i dir

La lógica de los grep en serie es (no es un comentario) y (coincide con dir)


Si desea hacer coincidir un carácter para negar una palabra similar a negar la clase de caracteres:

Por ejemplo, una cadena:

<? $str="aaa bbb4 aaa bbb7"; ?>

No utilice:

<? preg_match(''/aaa[^bbb]+?bbb7/s'', $str, $matches); ?>

Utilizar:

<? preg_match(''/aaa(?:(?!bbb).)+?bbb7/s'', $str, $matches); ?>

Fíjese en "(?!bbb)." no es ni mirar ni detrás ni mirar hacia delante; es lookcurrent, por ejemplo:

"(?=abc)abcde", "(?!abc)abcde"


Si desea que la prueba de expresiones regulares solo falle si la cadena completa coincide, lo siguiente funcionará:

^(?!hede$).*

por ejemplo, si desea permitir todos los valores excepto "foo" (es decir, "foofoo", "barfoo" y "foobar" pasarán, pero "foo" fallará), use: ^(?!foo$).*

Por supuesto, si está verificando la igualdad exacta , una mejor solución general en este caso es verificar la igualdad de la cadena, es decir,

myStr !== ''foo''

Incluso podría poner la negación fuera de la prueba si necesita características de expresiones regulares (aquí, insensibilidad de mayúsculas y minúsculas):

!/^[a-f]oo$/i.test(myStr)

Sin embargo, la solución de expresiones regulares en la parte superior de esta respuesta puede ser útil en situaciones donde se requiere una prueba de expresiones regulares positiva (tal vez por una API).


Tenga en cuenta que la solución no comienza con "hede" :

^(?!hede).*$

es generalmente mucho más eficiente que la solución para no contener "hede" :

^((?!hede).)*$

El primero verifica "hede" solo en la primera posición de la cadena de entrada, en lugar de en cada posición.


Si solo lo está utilizando para grep, puede usar grep -v hede para obtener todas las líneas que no contengan hede.

ETA Oh, releyendo la pregunta, grep -v es probablemente lo que entendiste por "opciones de herramientas".


A través del verbo PCRE (*SKIP)(*F)

^hede$(*SKIP)(*F)|^.*$

Esto hede completamente la línea que contiene la cadena exacta hede y coincide con todas las líneas restantes.

DEMO

Ejecución de las partes:

Consideremos la expresión regular anterior dividiéndola en dos partes.

  1. Parte antes del | símbolo. La parte no debe ser igualada .

    ^hede$(*SKIP)(*F)

  2. Parte después de la | símbolo. La parte debe ser emparejada .

    ^.*$

PARTE 1

El motor Regex comenzará su ejecución desde la primera parte.

^hede$(*SKIP)(*F)

Explicación:

  • ^ Afirma que estamos al principio.
  • hede Coincide con la cadena hede
  • $ Afirma que estamos al final de la línea.

Por lo tanto, la línea que contiene la cadena hede coincidirá. Una vez que el motor de expresiones regulares vea el siguiente (*SKIP)(*F) ( Nota: Podría escribir (*F) como verbo (*FAIL) ), salta y hace que la coincidencia falle. | se llama alteración u operador lógico O añadido al lado del verbo PCRE cuya entrada coincide con todos los límites existentes entre todos y cada uno de los caracteres de todas las líneas, excepto que la línea contiene la cadena exacta hede . Vea la demostración here . Es decir, intenta hacer coincidir los caracteres de la cadena restante. Ahora se ejecutaría la expresión regular en la segunda parte.

PARTE 2

^.*$

Explicación:

  • ^ Afirma que estamos al principio. es decir, coincide con todos los inicios de línea excepto el que está en la línea hede . Vea la demostración here .
  • .* En el modo multilínea,. coincidiría con cualquier carácter, excepto los caracteres de nueva línea o de retorno de carro. Y * repetiría el carácter anterior cero o más veces. Entonces .* Coincidiría con toda la línea. Vea la demostración here .

    Oye, ¿por qué agregó. * En lugar de. +?

    Porque .* Coincidiría con una línea en blanco pero .+ No coincidirá con un espacio en blanco. Queremos hacer coincidir todas las líneas excepto hede , puede haber una posibilidad de líneas en blanco también en la entrada. así que debes usar .* lugar de .+ . .+ repetiría el carácter anterior una o más veces. Ver .* Coincide con una línea en blanco here .

  • $ Fin de la línea de anclaje no es necesario aquí.


Responder:

^((?!hede).)*$

Explicación:

^ el principio de la cadena, ( grupo y captura a / 1 (0 o más veces (que coincida con la mayor cantidad posible)),
(?! mira adelante para ver si no hay,

hede tu cuerda,

) fin de la anticipación,. cualquier carácter excepto / n,
)* fin de / 1 (Nota: debido a que está utilizando un cuantificador en esta captura, solo la última repetición del patrón capturado se almacenará en / 1)
$ antes de un / n opcional, y el final de la cadena


La siguiente función le ayudará a obtener el resultado deseado.

<?PHP function removePrepositions($text){ $propositions=array(''//bfor/b/i'',''//bthe/b/i''); if( count($propositions) > 0 ) { foreach($propositions as $exceptionPhrase) { $text = preg_replace($exceptionPhrase, '''', trim($text)); } $retval = trim($text); } return $retval; } ?>


No entiendo la necesidad de expresiones regulares complejas o incluso de lookaheads aquí:

/hede|^(.*)$/gm

No coloque en un grupo de captura lo que no quiere, use uno para todo lo demás. Esto coincidirá con todas las líneas que no contengan "hede".


Con ConyEdit , puede utilizar la línea de comandos cc.gl !/hede/para obtener líneas que no contienen la coincidencia de expresiones regulares, o usar la línea de comandos cc.dl /hede/para eliminar las líneas que contienen la coincidencia de expresiones regulares. Tienen el mismo resultado.


El lenguaje TXR soporta la negación de expresiones regulares.

$ txr -c ''@(repeat) @{nothede /~hede/} @(do (put-line nothede)) @(end)'' Input

Un ejemplo más complicado: haga coincidir todas las líneas que comienzan con ay terminan con z, pero no contienen la subcadena hede:

$ txr -c ''@(repeat) @{nothede /a.*z&~.*hede.*/} @(do (put-line nothede)) @(end)'' - az <- echoed az abcz <- echoed abcz abhederz <- not echoed; contains hede ahedez <- not echoed; contains hede ace <- not echoed; does not end in z ahedz <- echoed ahedz

La negación de expresiones regulares no es particularmente útil por sí sola, pero cuando también tiene una intersección, las cosas se ponen interesantes, ya que tiene un conjunto completo de operaciones de conjuntos booleanos: puede expresar "el conjunto que coincide con esto, excepto los que coinciden con eso".


Puede ser más fácil mantener dos expresiones regulares en su código, una para hacer la primera coincidencia, y luego, si coincide, ejecute la segunda expresión regular para verificar casos atípicos que desea bloquear, por ejemplo, ^.*(hede).*entonces tenga la lógica apropiada en su código.

De acuerdo, admito que esto no es realmente una respuesta a la pregunta publicada y también puede usar un poco más de procesamiento que una sola expresión regular. Pero para los desarrolladores que vinieron aquí en busca de una solución de emergencia rápida para un caso atípico, esta solución no debe pasarse por alto.


Tal vez encuentre esto en Google al intentar escribir una expresión regular que sea capaz de hacer coincidir segmentos de una línea (en lugar de líneas completas) que no contienen una subcadena. Me tomó un tiempo para averiguar, así que voy a compartir:

Dada una cadena: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

Quiero hacer coincidir las <span>etiquetas que no contienen la subcadena "bad".

/<span(?:(?!bad).)*?>coincidirá <span class=/"good/">y <span class=/"ugly/">.

Observe que hay dos conjuntos (capas) de paréntesis:

  • El más interno es para el lookahead negativo (no es un grupo de captura)
  • Ruby interpretó lo más externo como grupo de captura, pero no queremos que sea un grupo de captura, así que agregué?: Al principio y ya no se interpreta como un grupo de captura.

Demo en Ruby:

s = ''<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>'' s.scan(/<span(?:(?!bad).)*?>/) # => ["<span class=/"good/">", "<span class=/"ugly/">"]


Una solución más simple es usar el operador no !

Su sentencia if deberá coincidir con "contiene" y no coincidir con "excluye".

var contains = /abc/; var excludes =/hede/; if(string.match(contains) && !(string.match(excludes))){ //proceed...

Creo que los diseñadores de RegEx anticiparon el uso de no operadores.