Tengo un valor como este:
"Foo Bar" "Another Value" something else
¿Qué expresión regular devolverá los valores encerrados entre 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 desean una explicación más profunda de cómo funciona esto, aquí hay una explicación del usuario ephemient :
([""'])
hacer coincidir una cita;((?=(\\?))\2.)
si existe una barra invertida, engánchela y, si eso sucede o no, haga coincidir un personaje;*?
coincidir muchas veces (sin avaricia, como para no comer la cita de cierre);\1
coincide con la misma cita que se usó para la apertura.
"foo\"
. El truco de mirar hacia adelante hace que el ?
cuantificador sea posesivo (incluso si el sabor de expresiones regulares no es compatible con la ?+
sintaxis o la agrupación atómica)
(["'])(?:\\.|[^\\])*?\1
En general, el siguiente fragmento de expresión regular es lo que está buscando:
"(.*?)"
Esto utiliza el no codicioso *? operador para capturar todo hasta, pero sin incluir la próxima 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']
"hello \" world"
"(.*?(?<!\\))"
Yo iría por:
"([^"]*)"
El [^ "] es una expresión regular para cualquier carácter, excepto ' ' '.
La razón por la que uso esto sobre el operador no codicioso es que tengo que seguir buscando eso solo para asegurarme de que estoy correcto.
Veamos dos formas eficientes de lidiar con las comillas escapadas. Estos patrones no están diseñados para ser concisos ni estéticos, sino para ser eficientes.
Estas formas usan la discriminación de primer carácter 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 probar las dos ramas 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 lidiar con cadenas que no tienen comillas balanceadas, puede usar cuantificadores posesivos en su lugar: [^"\\]*+(?:\\.[^"\\]*)*+
o una solución alternativa para emularlos, para evitar demasiado retroceso. También puede elegir que una parte entre comillas pueda ser una cotización de apertura hasta la próxima cotización (sin escape) o el final de la cadena. En este caso, no es necesario utilizar cuantificadores posesivos, solo debe hacer que la última cita sea opcional.
Aviso: a veces las citas no se escapan con una barra diagonal inversa, sino repitiendo 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 (quiero decir algo así (["']).....\1
) y usan una alternancia simple pero ["']
al principio, en factor.
Perl como:
["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
(tenga en cuenta que (?s:...)
es un azúcar sintáctico para activar el modo dotall / singleline dentro del grupo sin captura. Si esta sintaxis no es compatible, puede activar fácilmente este modo para todo el patrón o reemplazar el punto 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 de ECMA:
(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
POSIX extendido:
"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
o simplemente:
"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
/pattern/
sin escapar de nada (en lugar de la notación de objeto new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");
)
s
aquí: (?s:
y si coloca (?s)
algún lugar en el patrón.
El RegEx de respuesta aceptada devuelve los valores, incluidas las comillas circundantes: "Foo Bar"
y "Another Value"
como coincidencias.
Aquí hay RegEx que devuelve solo los valores entre comillas (como estaba pidiendo el interrogador):
Solo comillas dobles (use el valor del grupo de captura # 1):
"(.*?[^\\])"
Solo comillas simples (use el valor del grupo de captura # 1):
'(.*?[^\\])'
Ambos (use el valor del grupo de captura # 2):
(["'])(.*?[^\\])\1
-
Todo el apoyo escapó y cotizaciones anidadas.
src="(.*)"
pero obviamente estaba seleccionando todo antes del último ", su REGEX, sin embargo, seleccionó solo el contenido src =" ", pero no entendí cómo.
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 lo 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 hacia atrás positiva al comienzo (la ?<=
) y la mirada hacia adelante positiva al final (la ?=
). La mirada hacia atrás está mirando hacia atrás del personaje actual para verificar una cita, si se encuentra, comience desde allí y luego la búsqueda anticipada está verificando una cita para el personaje que está adelante y si se encuentra, deténgase en ese personaje. El grupo de retrospectiva (el ["']
) se envuelve entre paréntesis para crear un grupo para cualquier cotización que se encuentre al principio, luego se usa al final.(?=\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 cita final, se encontrará nuevamente por la búsqueda inicial que hace que coincida el texto entre las citas finales y las iniciales 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 sea posible. El bit que permite caracteres escapados en el medio lo tomé directamente de la respuesta de Adam.
El patrón (["'])(?:(?=(\\?))\2.)*?\1
anterior hace el trabajo, pero estoy preocupado por su rendimiento (no está mal, pero podría ser mejor). La mía debajo es ~ 20% más rápido.
El patrón "(.*?)"
es simplemente incompleto. Mi consejo para todos los que lean esto es ¡NO LO USE!
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 resto de ellos son tan "buenos" como el de arriba.
Si realmente te importa tanto el rendimiento como la precisión, comienza con el siguiente:
/(['"])((\\\1|.)*?)\1/gm
En mis pruebas, cubrió cada cadena que conocí, pero si encuentra algo que no funciona, con gusto lo actualizaría por usted.
Comprueba mi patrón en un probador de expresiones regulares en línea .
Me gustó la solución de Eugen Mihailescu para unir el contenido entre comillas y al mismo tiempo escapar de las comillas. Sin embargo, descubrí algunos problemas para escapar y se me ocurrió la siguiente expresión regular para solucionarlos:
(['"])(?:(?!\1|\\).|\\.)*\1
Hace el truco y sigue siendo bastante simple y fácil de mantener.
Demostración (con algunos casos de prueba más; no dude en usarlo y ampliarlo).
PD: si solo quieres el contenido entre comillas en la partida completa ( $0
), y no temes el uso de penalización de rendimiento:
(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)
Desafortunadamente, sin las comillas como anclas, tuve que agregar un límite \b
que no funciona bien con espacios y caracteres de límite sin palabras después de la cita inicial.
Alternativamente, modifique la versión inicial simplemente agregando un grupo y extraiga la forma de cadena$2
:
(['"])((?:(?!\1|\\).|\\.)*)\1
PPS: Si su enfoque es únicamente en la eficiencia, elija la solución de Casimir et Hippolyte ; es una buena.
-
, como en las coordenadas de longitud.
Esta versión
controla el retroceso
/(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
¡MÁS RESPUESTAS! Aquí está la solución que usé
\"([^\"]*?icon[^\"]*?)\"
TLDR;
reemplace el icono de la palabra con lo que está buscando en dichas citas y listo!
La forma en que esto funciona es que busca la palabra clave y no le importa qué más entre comillas. Por ejemplo:
id="fb-icon"
id="icon-close"
id="large-icon-close"
la expresión regular busca una comilla, "
luego busca cualquier grupo posible de letras que no sea "
hasta que encuentre icon
y cualquier grupo posible de letras que no "
sea, luego busca un cierre"
name="value"
con name={"value"}
ya que la expresión regular de esta respuesta regresa icon
/ value
como el segundo grupo (a diferencia de la respuesta aceptada). Buscar : =\"([^\"]*?[^\"]*?)\"
Reemplazar :={"$1"}
Me gustó la versión más expansiva de Axeman, pero tuve algunos problemas con ella (por ejemplo, no coincidía
foo "string \\ string" bar
o
foo "string1" bar "string2"
correctamente, así que intenté 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 salto de caracteres
" foo bar" "loloo"
. Sospecho que quería decir que para envolver en una cadena de texto, como lo hizo con la expresión regular: r'"\" foo bar\" \"loloo\""'
. Utilice las excelentes capacidades de formato de SO siempre que sea apropiado. No se trata solo de cosméticos; Literalmente, no podemos decir qué está tratando de decir si no los usa. ¡Y bienvenido a Stack Overflow !
A diferencia de la respuesta de Adam, tengo una simple pero trabajada:
(["'])(?:\\\1|.)*?\1
Y solo agregue paréntesis si desea obtener contenido entre comillas como esta:
(["'])((?:\\\1|.)*?)\1
Luego hace $1
coincidir el carácter entre comillas y la $2
cadena de contenido.
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'
Esto resultará en:> Foo Bar <> <> pero esto <
Aquí mostré la cadena de resultados entre> <'s para mayor claridad, también usando la versión no codiciosa con este comando sed primero tiramos la basura antes y después de ese ""' s y luego reemplazamos esto con la parte entre el "" 's y rodear esto por> <' s.
De Greg H. pude crear esta expresión regular para satisfacer mis necesidades.
Necesitaba hacer coincidir un valor específico que se calificaba al estar entre comillas. Debe ser una coincidencia completa, ninguna coincidencia parcial podría desencadenar un golpe
por ejemplo, "prueba" no pudo coincidir con "prueba2".
reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
print "winning..."
Cazador
Si está tratando de encontrar cadenas que solo tengan un sufijo determinado, como la sintaxis de puntos, puede intentar esto:
\"([^\"]*?[^\"]*?)\".localized
¿Dónde .localized
está 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
no "but this is not"
.
Una respuesta complementaria para el subconjunto de codificadores de Microsoft VBA solo uno usa la biblioteca Microsoft VBScript Regular Expressions 5.5
y esto proporciona 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
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
Todas las respuestas anteriores son buenas ... ¡excepto que NO admiten todos los caracteres Unicode! en ECMA Script (Javascript)
Si es un usuario de Node, es posible que desee la versión modificada de la respuesta aceptada que admite todos los caracteres unicode:
/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu
Tratar aquí .
? The preceding token is not quantifiable