2012-03-15 11 views
7

Quiero construir una expresión regular que coincida con ' o " y luego coincida con otros caracteres, que termina cuando se corresponde un ' o un " respectivamente, dependiendo de lo que se encontró en el comienzo. Por lo tanto, este problema parece ser lo suficientemente simple como para resolverlo con el uso de una referencia inversa al final; aquí está por debajo de un cierto código expresiones regulares (que es en Java por lo que importa los caracteres de escape adicionales, tales como la \ antes de la "):Regex; hacer una referencia inversa de un carácter que NO coincidió en un conjunto de caracteres

private static String seekerTwo = "(['\"])([a-zA-Z])([a-zA-Z0-9():;/`\\=\\.\\,\\- ]+)(\\1)"; 

Este código va a tratar con éxito con cosas tales como:

"hello my name is bob" 
'i live in bethnal green' 

El problemas viene cuando tengo una cadena como esta:

"hello this seat 'may be taken' already" 

el uso de la expresión regular por encima de él no en la parte inicial al encontrarse ' y luego continuaría y coincidir con éxito 'may be taken' ... pero esto es obviamente insuficiente, necesito que coincida toda la cadena.

Lo que estoy pensando, es que necesito una forma de ignorar el tipo de comillas, que NO se correspondía en el primer grupo, incluyéndolo como un personaje en el conjunto de caracteres del tercer grupo. Sin embargo, no sé de ninguna manera para hacer esto. ¿Hay algún tipo de función de retro-referencia furtiva NO o algo así? ¿Algo que puedo usar para hacer referencia al personaje en el primer grupo que NO se combinó? ¿O de lo contrario algún tipo de solución a mi situación?

+0

Hola y bienvenidos a StackOverflow. Me he tomado la libertad de volver a formatear tu publicación un poco. Puede hacer clic en el enlace editar para ver cómo lo hice. Es muy importante saber si necesita publicar el código ... –

Respuesta

12

Esto se puede hacer usando lookahead assertions negativo. La siguiente solución aún tiene en cuenta que se podía escapar de una cita dentro de una cadena:

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

Explicación:

(["']) # Match and remember a quote. 
(?:  # Either match... 
\\.  # an escaped character 
|   # or 
(?!\1) # (unless that character is identical to the quote character in \1) 
.  # any character 
)*  # any number of times. 
\1  # Match the corresponding quote. 

Esto coincide correctamente "hello this seat 'may be taken' already" o "hello this seat \"may be taken\" already".

En Java, con todas las barras invertidas:

Pattern regex = Pattern.compile(
    "([\"']) # Match and remember a quote.\n" + 
    "(?:  # Either match...\n" + 
    " \\\\. # an escaped character\n" + 
    "|   # or\n" + 
    " (?!\\1) # (unless that character is identical to the matched quote char)\n" + 
    " .  # any character\n" + 
    ")*  # any number of times.\n" + 
    "\\1  # Match the corresponding quote", 
    Pattern.COMMENTS); 
+0

+1 para una solución bien pensada y explicada. – FloppyDisk

+0

Excelente trabajo allí Tim, y gracias por editar mi publicación. Gracias a su sugerencia, con un poco de trabajo modifiqué mi código así: "(['\"]) ([a-zA-Z]) ((?! \\ 1) [a-zA-Z0-9():;/''\" \\ = \\. \\, \\ -]) + (\\ 1) "por lo que su solución fue lo suficientemente simple y perfectamente efectiva; agregue el equivalente de una expresión regular si la declaración anterior al conjunto de caracteres principal, que se saltará directamente al último ciclo. Y agregue ambos tipos de citas al conjunto principal de caracteres. De esta forma, si se encuentra la char de la cita encontrada al inicio en cualquier momento, la expresión regular terminará y regresará. Bonito. –

2

solución de Tim funciona bastante bien si se puede usar lookaround (que Java hace de soporte). Pero si usted se encuentra el uso de un lenguaje o herramienta que no sea compatible con lookaround, simplemente podría coincidir ambos casos (cuerdas dobles citados y cadenas entre comillas sencillas) por separado:

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

partidos cada caso por separado, pero devuelve cualquiera de los casos como todo el partido


Sin embargo

Ambos casos pueden ser víctimas de al menos una eventualidad. Si no se mira de cerca, usted puede pensar que debe haber dos partidos en este extracto:

Se volvió a subir a su moto."Te veré más tarde, cuando haya terminado con todo esto", dijo, mirando hacia atrás por un momento antes de comenzar su viaje. Al entrar en la calle, uno de los carritos de la ciudad colisionó con la bicicleta de Mike. "¡Oh mi!" exclamó un espectador.

... pero hay tres partidos, no dos:

"I'll see you later, when I'm done with all this" 
's trolleys collided with Mike' 
"Oh my!" 

y este extracto contiene sólo UNO partido:

La lucha no había terminado , aunque. "¡Oye!" gritó Bob. "¿Qué deseas?" Repliqué. "¡Odio tu carácter!" "¿Por qué me importaría?" "¡Porque te amo!" "¿Tú lo haces?" Bob hizo una pausa por un momento antes de susurrar "¡No, no podría amarte!"

¿Lo puede encontrar? : D

't over yet, though. "Hey!" yelled Bob. "What do you want?" I retorted. "I hate your guts!" "Why would I care?" "Because I love you!" "You do?" Bob paused for a moment before whispering "No, I couldn' 

yo recomendaría (si usted está listo para el uso lookaround), que considere la posibilidad de hacer algunas comprobación adicional (como una búsqueda hacia atrás positivo para los espacios en blanco o similares antes de la primera cita) para asegurarse de que usted don' t coincide con cosas como 's trolleys collided with Mike' - aunque no pondría mucho dinero en ninguna solución sin muchas pruebas primero. Añadiendo (?<=\s|^) al inicio de cualquiera de las expresiones evitará los casos anteriores ... es decir:

(?<=\s|^)(["'])(?:\\.|(?!\1).)*\1     #based on Tim's 

o

(?<=\s|^)("(\\"|[^"])*"|'(\\'|[^'])*')    #based on my alternative 

No estoy seguro de cómo lookaround eficiente se compara con la no lookaround, por lo que la dos arriba pueden ser equivalentes, o uno puede ser más eficiente que el otro (?)

+0

Algunos puntos buenos aquí Code Jockey, y de hecho, analizar el texto en inglés de esta manera no sería acertado. Sin embargo, en realidad estoy tratando de analizar el texto ruso en el código MySQL (cambié el а-яА-ЯёЁ a-zA-Z en mi código anterior, para que la gente aquí pueda captar el significado), y al analizar Cadenas en el código, por supuesto, siempre se garantiza que estén encerrados entre un tipo de comillas o el otro. –

Cuestiones relacionadas