una regulares reemplazar quitar funcion expresiones especiales eliminar elementos como caracteres cadenas cadena python regex

python - regulares - Regex para administrar caracteres escapados para elementos como literales de cadenas



quitar de una cadena python (6)

Creo que esto funcionará

import re regexc = re.compile(r"(?:^|[^//])''(([^//']|//'|////)*)''") def check(test, base, target): match = regexc.search(base) assert match is not None, test+": regex didn''t match for "+base assert match.group(1) == target, test+": "+target+" not found in "+base print "test %s passed"%test check("Empty","''''","") check("single escape1", r""" Example: ''Foo /' Bar'' End. """,r"Foo /' Bar") check("single escape2", r"""''/'''""",r"/'") check("double escape",r""" Example2: ''Foo //' End. """,r"Foo //") check("First quote escaped",r"not matched/'''a''","a") check("First quote escaped beginning",r"/'''a''","a")

La expresión regular r"(?:^|[^//])''(([^//']|//'|////)*)''" hace coincidir solo las cosas que queremos dentro del cuerda:

  1. Caracteres que no son barras invertidas o comillas.
  2. Cita escapada
  3. Barra invertida escapada

EDITAR:

Agregue expresiones regulares adicionales al frente para verificar la primera cita escapada.

Me gustaría poder hacer coincidir un literal de cadena con la opción de citas escapadas. Por ejemplo, me gustaría poder buscar "esto es una" prueba con ''valores'' escapados ''ok'' y hacer que reconozca correctamente la barra diagonal inversa como un carácter de escape. He intentado soluciones como las siguientes:

import re regexc = re.compile(r"/'(.*?)(?<!//)/'") match = regexc.search(r""" Example: ''Foo /' Bar'' End. """) print match.groups() # I want ("Foo /' Bar") to be printed above

Después de mirar esto, hay un problema simple que el carácter de escape que se usa, " / ", no se puede escapar por sí mismo. No puedo entender cómo hacer eso. Quería una solución como la siguiente, pero las aserciones de observación negativas deben ser de longitud fija:

# ... re.compile(r"/'(.*?)(?<!//(////)*)/'") # ...

¿Algún gurú regex capaz de abordar este problema? Gracias.


El patrón de Douglas Leeder ( (?:^|[^//])''(([^//']|//'|////)*)'' no coincidirá con la "test ''test /x3F test'' test" y "test //'test'' test" . (Cadena que contiene un escape distinto de comillas y barras diagonales, y cadena precedida por una barra invertida escapada.)

El patrón de cletus ( (?<!//)''((?://'|[^''])*)(?<!//)'' no coincidirá con "test ''test//' test" . (Cadena que termina con una barra invertida escapada.)

Mi propuesta para cadenas de comillas simples es esta:

(?<!//)(?:////)*''((?://.|[^//'])*)''

Para las picaduras de una sola cita o doble cita, podría usar esto:

(?<!//)(?:////)*("|'')((?://.|(?!/1)[^//])*)/1

Prueba de ejecución usando Python:

Doublas Leeder´s test cases: "''''" matched successfully: "" " Example: ''Foo /' Bar'' End. " matched successfully: "Foo /' Bar" "''/'''" matched successfully: "/'" " Example2: ''Foo //' End. " matched successfully: "Foo //" "not matched/'''a''" matched successfully: "a" "/'''a''" matched successfully: "a" cletus´ test cases: "''testing 123''" matched successfully: "testing 123" "''testing 123//'" matched successfully: "testing 123//" "''testing 123" didn´t match, as exected. "blah ''testing 123" didn´t match, as exected. "blah ''testing 123''" matched successfully: "testing 123" "blah ''testing 123'' foo" matched successfully: "testing 123" "this ''is a /' test''" matched successfully: "is a /' test" "another /' test ''testing /' 123'' /' blah" matched successfully: "testing /' 123" MizardX´s test cases: "test ''test /x3F test'' test" matched successfully: "test /x3F test" "test //'test'' test" matched successfully: "test" "test ''test//' test" matched successfully: "test//"


Si entiendo lo que estás diciendo (y no estoy seguro de hacerlo), quieres encontrar la cadena entrecomillada dentro de tu cadena ignorando las comillas escapadas. ¿Está bien? Si es así, intente esto:

/(?<!//)''((?://'|[^''])*)(?<!//)''/

Básicamente:

  • Comience con una comilla simple que no esté precedida por una barra diagonal inversa;
  • Coincide con cero o más ocurrencias de: barra invertida, luego cita o cualquier carácter que no sea una cita;
  • Termine en una cita;
  • No agrupe los paréntesis del medio (el operador?:); y
  • La cotización de cierre no puede ir precedida de una barra invertida.

Ok, he probado esto en Java (lo siento, es más mi schtick que Python, pero el principio es el mismo):

private final static String TESTS[] = { "''testing 123''", "''testing 123//'", "''testing 123", "blah ''testing 123", "blah ''testing 123''", "blah ''testing 123'' foo", "this ''is a //' test''", "another //' test ''testing //' 123'' //' blah" }; public static void main(String args[]) { Pattern p = Pattern.compile("(?<!////)''((?:////'|[^''])*)(?<!////)''"); for (String test : TESTS) { Matcher m = p.matcher(test); if (m.find()) { System.out.printf("%s => %s%n", test, m.group(1)); } else { System.out.printf("%s doesn''t match%n", test); } } }

resultados:

''testing 123'' => testing 123 ''testing 123/' doesn''t match ''testing 123 doesn''t match blah ''testing 123 doesn''t match blah ''testing 123'' => testing 123 blah ''testing 123'' foo => testing 123 this ''is a /' test'' => is a /' test another /' test ''testing /' 123'' /' blah => testing /' 123

que parece correcto


re_single_quote = r " ''[^''//]*(?://.[^''//]*)*''"

En primer lugar, tenga en cuenta que la respuesta de MizardX es 100% precisa. Me gustaría agregar algunas recomendaciones adicionales con respecto a la eficiencia. En segundo lugar, me gustaría señalar que este problema se resolvió y optimizó hace mucho tiempo. Consulte: Dominio de expresiones regulares (3ª edición) , (que cubre este problema específico en gran detalle, muy recomendable).

Primero veamos la sub-expresión para hacer coincidir una sola cadena entrecomillada que puede contener comillas simples escapadas. Si va a permitir comillas simples escapadas, es mejor que al menos también permita escapar-escapes (que es lo que hace la respuesta de Douglas Leeder). Pero siempre que lo hagas, es igual de fácil permitir escapadas, cualquier cosa. Con estos requisitos MizardX es el único que obtuvo la expresión correcta. Aquí está tanto en formato corto como largo (y me he tomado la libertad de escribir esto en modo VERBOSE , con muchos comentarios descriptivos, que siempre debes hacer para expresiones regulares no triviales):

# MizardX''s correct regex to match single quoted string: re_sq_short = r"''((?://.|[^//'])*)''" re_sq_long = r""" '' # Literal opening quote ( # Capture group $1: Contents. (?: # Group for contents alternatives //. # Either escaped anything | [^//'] # or one non-quote, non-escape. )* # Zero or more contents alternatives. ) # End $1: Contents. '' """

Esto funciona y coincide correctamente con todos los casos de prueba de cadena siguientes:

text01 = r"out1 ''escaped-escape: // '' out2" test02 = r"out1 ''escaped-quote: /' '' out2" test03 = r"out1 ''escaped-anything: /X '' out2" test04 = r"out1 ''two escaped escapes: //// '' out2" test05 = r"out1 ''escaped-quote at end: /''' out2" test06 = r"out1 ''escaped-escape at end: //' out2"

Ok, ahora vamos a comenzar a mejorar en esto. Primero, el orden de las alternativas hace una diferencia y uno siempre debe poner la alternativa más probable primero. En este caso, los caracteres no escapados son más probables que los escapados, por lo que invertir el orden mejorará la eficacia de la expresión regular de la siguiente manera:

# Better regex to match single quoted string: re_sq_short = r"''((?:[^//']|//.)*)''" re_sq_long = r""" '' # Literal opening quote ( # $1: Contents. (?: # Group for contents alternatives [^//'] # Either a non-quote, non-escape, | //. # or an escaped anything. )* # Zero or more contents alternatives. ) # End $1: Contents. '' """

"Desenrollar el bucle":

Esto es un poco mejor, pero se puede mejorar aún más (significativamente) aplicando la técnica de eficiencia de "desenrollar el bucle" de Jeffrey Friedl (de MRE3 ). La expresión regular anterior no es óptima porque debe aplicar concienzudamente el cuantificador en estrella al grupo sin captura de dos alternativas, cada una de las cuales consume solo uno o dos caracteres a la vez. Esta alternancia se puede eliminar por completo al reconocer que un patrón similar se repite una y otra vez, y que una expresión equivalente se puede diseñar para hacer lo mismo sin alternancia. Aquí hay una expresión optimizada para hacer coincidir una sola cadena entrecomillada y capturar su contenido en el grupo $1 :

# Better regex to match single quoted string: re_sq_short = r"''([^''//]*(?://.[^''//]*)*)''" re_sq_long = r""" '' # Literal opening quote ( # $1: Contents. [^''//]* # {normal*} Zero or more non-'', non-escapes. (?: # Group for {(special normal*)*} construct. //. # {special} Escaped anything. [^''//]* # More {normal*}. )* # Finish up {(special normal*)*} construct. ) # End $1: Contents. '' """

Esta expresión engulle todas las comillas sin comillas (la gran mayoría de las cadenas), en un "trago", que reduce drásticamente la cantidad de trabajo que debe realizar el motor de expresiones regulares. ¿Cuánto mejor preguntas? Bueno, ingresé cada una de las expresiones presentadas de esta pregunta en RegexBuddy y medí cuántos pasos le tomó al motor de expresiones regulares completar una coincidencia en la siguiente cadena (que todas las soluciones coinciden correctamente):

''This is an example string which contains one /'internally quoted/' string.''

Estos son los resultados del benchmark en la cadena de prueba anterior:

r""" AUTHOR SINGLE-QUOTE REGEX STEPS TO: MATCH NON-MATCH Evan Fosmark ''(.*?)(?<!//)'' 374 376 Douglas Leeder ''(([^//']|//'|////)*)'' 154 444 cletus/PEZ ''((?://'|[^''])*)(?<!//)'' 223 527 MizardX ''((?://.|[^//'])*)'' 221 369 MizardX(improved) ''((?:[^//']|//.)*)'' 153 369 Jeffrey Friedl ''([^//']*(?://.[^//']*)*)'' 13 19 """

Estos pasos son la cantidad de pasos necesarios para unir la cadena de prueba utilizando la función de depuración RegexBuddy. La columna "NO CORRESPONDIENTE" es la cantidad de pasos necesarios para declarar una falla de coincidencia cuando se elimina la cotización de cierre de la cadena de prueba. Como puede ver, la diferencia es significativa para los casos coincidentes y no coincidentes. Tenga en cuenta también que estas mejoras de eficiencia solo se aplican a un motor de NFA que utiliza el rastreo (es decir, Perl, PHP, Java, Python, Javascript, .NET, Ruby y muchos otros). Un motor de DFA no verá ningún aumento de rendimiento mediante esta técnica ( Ver: la coincidencia de expresión regular puede ser simple y rápida ).

En a la solución completa:

El objetivo de la pregunta original (mi interpretación) es seleccionar las subcadenas citadas (que pueden contener comillas escapadas) de una cadena más grande. Si se sabe que el texto que está fuera de las subcadenas entre comillas nunca contendrá comillas simples escapadas, la expresión regular anterior hará el trabajo. Sin embargo, para correlacionar correctamente las subcadenas de una sola cita dentro de un mar de texto nadando con citas escapadas y escapes de escapes y escapes-cosas-cosas, (que es mi interpretación de lo que el autor está buscando), requiere un análisis desde el principio de la cadena No, (esto es lo que originalmente pensé), pero no se puede lograr con la expresión muy inteligente (?<!//)(?:////)* . Aquí hay algunas cadenas de prueba para ejercitar las diversas soluciones:

text01 = r"out1 ''escaped-escape: // '' out2" test02 = r"out1 ''escaped-quote: /' '' out2" test03 = r"out1 ''escaped-anything: /X '' out2" test04 = r"out1 ''two escaped escapes: //// '' out2" test05 = r"out1 ''escaped-quote at end: /''' out2" test06 = r"out1 ''escaped-escape at end: //' out2" test07 = r"out1 ''str1'' out2 ''str2'' out2" test08 = r"out1 /' ''str1'' out2 ''str2'' out2" test09 = r"out1 ///' ''str1'' out2 ''str2'' out2" test10 = r"out1 // ''str1'' out2 ''str2'' out2" test11 = r"out1 //// ''str1'' out2 ''str2'' out2" test12 = r"out1 //'str1'' out2 ''str2'' out2" test13 = r"out1 ////'str1'' out2 ''str2'' out2" test14 = r"out1 ''str1''''str2''''str3'' out2"

Teniendo en cuenta estos datos de prueba, veamos cómo les va a las distintas soluciones (''p'' == pass, ''XX'' == fallan):

r""" AUTHOR/REGEX 01 02 03 04 05 06 07 08 09 10 11 12 13 14 Douglas Leeder p p XX p p p p p p p p XX XX XX r"(?:^|[^//])''(([^//']|//'|////)*)''" cletus/PEZ p p p p p XX p p p p p XX XX XX r"(?<!//)''((?://'|[^''])*)(?<!//)''" MizardX p p p p p p p p p p p p p p r"(?<!//)(?:////)*''((?://.|[^//'])*)''" ridgerunner p p p p p p p p p p p p p p r"(?<!//)(?:////)*''([^''//]*(?://.[^''//]*)*)''" """

Un script de prueba en funcionamiento:

import re data_list = [ r"out1 ''escaped-escape: // '' out2", r"out1 ''escaped-quote: /' '' out2", r"out1 ''escaped-anything: /X '' out2", r"out1 ''two escaped escapes: //// '' out2", r"out1 ''escaped-quote at end: /''' out2", r"out1 ''escaped-escape at end: //' out2", r"out1 ''str1'' out2 ''str2'' out2", r"out1 /' ''str1'' out2 ''str2'' out2", r"out1 ///' ''str1'' out2 ''str2'' out2", r"out1 // ''str1'' out2 ''str2'' out2", r"out1 //// ''str1'' out2 ''str2'' out2", r"out1 //'str1'' out2 ''str2'' out2", r"out1 ////'str1'' out2 ''str2'' out2", r"out1 ''str1''''str2''''str3'' out2", ] regex = re.compile( r"""(?<!//)(?:////)*''([^''//]*(?://.[^''//]*)*)''""", re.DOTALL) data_cnt = 0 for data in data_list: data_cnt += 1 print ("/nData string %d" % (data_cnt)) m_cnt = 0 for match in regex.finditer(data): m_cnt += 1 if (match.group(1)): print(" quoted sub-string%3d = /"%s/"" % (m_cnt, match.group(1)))

¡Uf!

ps Gracias a MizardX por la genial (?<!//)(?:////)* expresión. ¡Aprenda algo nuevo cada día!


>>> print re.findall(r"(''([^''//]|//'|////)*'')",r""" Example: ''Foo /' Bar'' End. """)[0][0]

''Foo /' Bar ''


Usando la expresión de cletus con re.findall de Python ():

re.findall(r"(?<!//)''((?://'|[^''])*)(?<!//)''", s)

Una prueba que encuentra varias coincidencias en una cadena:

>>> re.findall(r"(?<!//)''((?://'|[^''])*)(?<!//)''", r"/'''foo bar gazonk'' foo ''bar'' gazonk ''foo /'bar/' gazonk'' ''gazonk bar foo/'") [''foo bar gazonk'', ''bar'', "foo //'bar//' gazonk"] >>>

Usando el conjunto de cadenas TEST de cletus:

["%s => %s" % (s, re.findall(r"(?<!//)''((?://'|[^''])*)(?<!//)''", s)) for s in TESTS]

Funciona de maravilla. (Pruébelo usted mismo o tome mi palabra para eso).