RegEx: agarrar valores entre comillas

Tengo un valor como este:

"Foo Bar" "Another Value" something else 

¿Qué expresión regular devolverá los valores incluidos en las comillas (por ejemplo, Foo Bar y Another Value )?

He estado usando lo siguiente con gran éxito:

 (["'])(?:(?=(\\?))\2.)*?\1 

También admite comillas anidadas.

Para aquellos que quieren una explicación más profunda de cómo funciona esto, aquí hay una explicación del usuario ephemient :

([""']) coincide con una cita; ((?=(\\?))\2.) Si la barra invertida existe, engullirla, y ya sea que eso suceda, haga coincidir un carácter; *? coincidir muchas veces (no codicioso, como para no comer la cita de cierre); \1 coincide con la misma cita que se usó para abrir.

En general, el siguiente fragmento de expresión regular es lo que estás buscando:

 "(.*?)" 

Esto usa el no codicioso *? operador para capturar todo hasta, pero sin incluir, la siguiente comilla doble. Luego, utiliza un mecanismo específico del idioma para extraer el texto coincidente.

En Python, podrías hacer:

 >>> import re >>> string = '"Foo Bar" "Another Value"' >>> print re.findall(r'"(.*?)"', string) ['Foo Bar', 'Another Value'] 

Yo iría por:

 "([^"]*)" 

El [^ “] es regex para cualquier caracter excepto ‘
La razón por la que uso esto para muchos operadores no codiciosos es que tengo que seguir buscando para asegurarme de que lo haga correctamente.

Veamos dos maneras eficientes que se ocupan de las comillas escapadas. Estos patrones no están diseñados para ser concisos ni estéticos, sino para ser eficientes.

Estas formas usan la primera discriminación de caracteres para encontrar rápidamente comillas en la cadena sin el costo de una alternancia. (La idea es descartar rápidamente los caracteres que no son comillas sin para probar las dos twigs de la alternancia).

El contenido entre comillas se describe con un bucle desenrollado (en lugar de una alternancia repetida) para ser más eficiente también: [^"\\]*(?:\\.[^"\\]*)*

Obviamente, para tratar con cadenas que no tienen comillas equilibradas, puede usar cuantificadores posesivos en su lugar: [^"\\]*+(?:\\.[^"\\]*)*+ o una solución para emularlas, para evitar demasiado retroceso. También puede elegir que una parte entre comillas puede ser una cita de apertura hasta la próxima cita (no escapada) o el final de la cadena. En este caso, no es necesario utilizar cuantificadores posesivos, solo necesita hacer que la última cita sea opcional.

Aviso: algunas veces, las comillas no se escapan con una barra diagonal inversa sino que se repite la cita. En este caso, el subpatrón de contenido se ve así: [^"]*(?:""[^"]*)*

Los patrones evitan el uso de un grupo de captura y una referencia inversa (me refiero a algo así como (["']).....\1 ) y utilizan una alternancia simple pero con ["'] al principio, en factor.

Perl gusta:

 ["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*') 

(tenga en cuenta que (?s:...) es un azúcar sintáctico para activar el modo dotall / singleline dentro del grupo que no captura. Si esta syntax no es compatible, puede cambiar fácilmente este modo para todo el patrón o reemplazar el dot con [\s\S] )

(La forma en que se escribe este patrón es totalmente "manual" y no tiene en cuenta las eventuales optimizaciones internas del motor)

Script ECMA:

 (?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*') 

POSIX extendido:

 "[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*' 

o simplemente:

 "([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*' 

Una respuesta muy tardía, pero me gusta responder

 (\"[\w\s]+\") 

http://regex101.com/r/cB0kB8/1

Curiosamente, ninguna de estas respuestas produce una expresión regular donde la coincidencia devuelta es el texto dentro de las comillas, que es lo que se solicita. MA-Madden intenta pero solo obtiene la partida interna como un grupo capturado en lugar de la partida completa. Una forma de hacerlo sería:

 (?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1) 

Se pueden ver ejemplos de esto en esta demostración https://regex101.com/r/Hbj8aP/1

La clave aquí es la mirada positiva detrás del inicio (el ?<= ) Y la anticipación positiva al final (el ?= ). El investigador busca detrás del personaje actual para buscar una cotización, si la encuentra, comienza a partir de ahí y luego la búsqueda anticipada está verificando que el personaje tenga una cotización y si se encuentra, deténgase en ese personaje. El grupo lookbehind (el ["'] ) está entre corchetes para crear un grupo para cualquier cita que se encuentre al principio, luego se usa al final lookahead (?=\1) para asegurarse de que solo se detiene cuando encuentra la cita correspondiente.

La única otra complicación es que, debido a que la búsqueda anticipada en realidad no consume la cotización final, se encontrará de nuevo con la apariencia inicial que hace coincidir el texto entre las cotizaciones finales y de inicio en la misma línea. Poner un límite de palabras en la cita de apertura ( ["']\b ) ayuda con esto, aunque idealmente me gustaría pasar de la búsqueda anticipada, pero no creo que eso sea posible. El bit que permite a los personajes escapados en el medio. He tomado directamente de la respuesta de Adam.

Esta versión

  • cuentas para citas escapadas
  • controla el retroceso

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

El patrón (["'])(?:(?=(\\?))\2.)*?\1 hace el trabajo, pero me preocupan sus resultados (no está mal, pero podría ser mejor). debajo es ~ 20% más rápido.

El patrón "(.*?)" Está incompleto. Mi consejo para todos los que lean esto es ¡NO LO UTILICEN!

Por ejemplo, no puede capturar muchas cadenas (si es necesario puedo proporcionar un caso de prueba exhaustivo) como el siguiente:

$ string = ‘¿Cómo estás? Estoy bien, gracias ‘;

El rest de ellos son tan “buenos” como el de arriba.

Si realmente te interesan tanto el rendimiento como la precisión, comienza con el siguiente:

/(['"])((\\\1|.)*?)\1/gm

En mis pruebas cubrió cada cadena que encontré, pero si encuentras algo que no funciona, con mucho gusto lo actualizaré por ti.

Verifique mi patrón en un probador de expresiones regulares en línea .

El RegEx de la respuesta aceptada devuelve los valores, incluidas las comillas que rodean: "Foo Bar" y "Another Value" como coincidencias.

Aquí hay RegEx que devuelve solo los valores entre comillas (como preguntaba el interrogador):

Solo comillas dobles (use el valor del grupo de captura n. ° 1):

"(.*?[^\\])"

Solo comillas simples (valor de uso del grupo de captura n. ° 1):

'(.*?[^\\])'

Ambos (valor de uso del grupo de captura n. ° 2):

(["'])(.*?[^\\])\1

Todo el soporte se escapó y las comillas anidadas.

Me gustó la versión más expansiva de Axeman, pero tuve algunos problemas con ella (no coincidía, por ejemplo,

 foo "string \\ string" bar 

o

 foo "string1" bar "string2" 

correctamente, así que traté de arreglarlo:

 # opening quote (["']) ( # repeat (non-greedy, so we don't span multiple strings) (?: # anything, except not the opening quote, and not # a backslash, which are handled separately. (?!\1)[^\\] | # consume any double backslash (unnecessary?) (?:\\\\)* | # Allow backslash to escape characters \\. )*? ) # same character as opening quote \1 
 string = "\" foo bar\" \"loloo\"" print re.findall(r'"(.*?)"',string) 

solo prueba esto, funciona como un encanto!

\ indica carácter de salto

¡MÁS RESPUESTAS! Aquí está la solución que utilicé

\"([^\"]*?icon[^\"]*?)\"

TLDR;
reemplace el ícono de palabra con lo que busca en dichas citas y ¡listo!


La forma en que esto funciona es buscar la palabra clave y no importa qué más entre las comillas. P.EJ:
id="fb-icon"
id="icon-close"
id="large-icon-close"
la expresión regular busca una comilla "
entonces busca cualquier posible grupo de letras que no sea "
hasta que encuentre el icon
y cualquier posible grupo de letras que no sea "
luego busca un cierre "

De Greg H. Pude crear esta expresión regular para satisfacer mis necesidades.

Necesitaba hacer coincidir un valor específico calificado por estar dentro de las comillas. Debe ser una coincidencia completa, ninguna coincidencia parcial podría desencadenar un golpe

por ejemplo, “prueba” no podría coincidir con “prueba2”.

 reg = r"""(['"])(%s)\1""" if re.search(reg%(needle), haystack, re.IGNORECASE): print "winning..." 

Cazador

Me gustó la solución de Eugen Mihailescu para hacer coincidir el contenido entre comillas, mientras que permite escapar de las comillas. Sin embargo, descubrí algunos problemas con el escape y se me ocurrió la siguiente expresión regular para corregirlos:

 (['"])(?:(?!\1|\\).|\\.)*\1 

Hace el truco y sigue siendo bastante simple y fácil de mantener.

Demostración (con algunos casos de prueba más, siéntete libre de usarlo y expandirlo).


PD: si solo quiere el contenido entre las comillas en la coincidencia completa ( $0 ) y no tiene miedo de la penalización de rendimiento, use:

 (?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1) 

PPS: si su atención se centra únicamente en la eficiencia, vaya con la solución de Casimir et Hippolyte ; es una buena.

 echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1 

Esto dará como resultado:> Foo Bar <> <> pero esto <

Aquí mostré la cadena de resultados entre> <'s.

Para mí trabajó este:

 |([\'"])(.*?)\1|i 

Lo he usado en una oración como esta:

 preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches); 

y funcionó muy bien.

Si intentas encontrar cadenas que solo tengan un determinado sufijo, como la syntax de puntos, puedes probar esto:

\"([^\"]*?[^\"]*?)\".localized

Donde .localized es el sufijo.

Ejemplo:

print("this is something I need to return".localized + "so is this".localized + "but this is not")

Capturará "this is something I need to return".localized y "so is this".localized pero no "but this is not" .

Una respuesta suplementaria para el subconjunto de codificadores de Microsoft VBA solo uno usa la biblioteca Microsoft VBScript Regular Expressions 5.5 y esto le da el siguiente código

 Sub TestRegularExpression() Dim oRE As VBScript_RegExp_55.RegExp '* Tools->References: Microsoft VBScript Regular Expressions 5.5 Set oRE = New VBScript_RegExp_55.RegExp oRE.Pattern = """([^""]*)""" oRE.Global = True Dim sTest As String sTest = """Foo Bar"" ""Another Value"" something else" Debug.Assert oRE.test(sTest) Dim oMatchCol As VBScript_RegExp_55.MatchCollection Set oMatchCol = oRE.Execute(sTest) Debug.Assert oMatchCol.Count = 2 Dim oMatch As Match For Each oMatch In oMatchCol Debug.Print oMatch.SubMatches(0) Next oMatch End Sub 

A diferencia de la respuesta de Adam, tengo uno simple pero trabajado:

 (["'])(?:\\\1|.)*?\1 

Y solo agregue paréntesis si desea obtener contenido entre comillas como este:

 (["'])((?:\\\1|.)*?)\1 

Luego $1 coincide con el comillas char y $2 coincide con el cadena de contenido.