Pregunta

Ok, tengo una cadena multilínea en la que estoy tratando de hacer un poco de limpieza.

Cada línea puede o no formar parte de un bloque grande de texto citado. Ejemplo:

This line is not quoted.
This part of the line is not quoted “but this is.”
This one is not quoted either.
“This entire line is quoted”
Not quoted.
“This line is quoted
and so is this one
and so is this one.”
This is not quoted “but this is
and so is this.”

Necesito un reemplazo RegEx que desenvuelva las líneas entrecortadas, es decir, reemplace " \ r \ n " con un espacio, pero solo entre las comillas rizadas.

Así es como debe verse después del reemplazo:

This line is not quoted.
This part of the line is not quoted “but this is.”
This one is not quoted either.
“This entire line is quoted”
Not quoted.
“This line is quoted and so is this one and so is this one.”
This is not quoted “but this is and so is this.”

(Observe cómo las dos últimas líneas eran líneas múltiples en el texto de entrada).

Controles

  • Lo ideal es que necesites una sola llamada de reemplazo Regex
  • Uso de la biblioteca .NET RegEx
  • Las comillas son siempre comillas de inicio / finalización, no son simples tics ("), lo que debería facilitarlo un poco.

Restricción importante

Esto no es un código .NET directo, estoy llenando una tabla de " searchfor / replacewith " cadenas que luego se llaman a través de RegEx.Replace. No tengo la capacidad de agregar código personalizado como Match Evaluators, hacer bucles a través de grupos capturados, etc.

Respuesta actual hasta el momento, algo similar a:

r.Replace("(?<=“)\r\n(?=”)", " ")

Obviamente, todavía no estoy cerca.

La misma lógica podría aplicarse, por ejemplo, a la codificación por colores de los comentarios de bloque en el código de programación: cualquier cosa dentro del comentario de bloque no se trata de la misma manera que las cosas fuera de los comentarios. (El código es un poco más complicado ya que los delimitadores de comentarios de inicio / finalización del bloque también pueden existir legítimamente dentro de una cadena literal, un problema con el que no tengo que lidiar aquí).

¿Fue útil?

Solución

Suponiendo que todas las citas en línea estén correctamente equilibradas, esta expresión regular debe hacer lo que usted quiere:

@"[\r\n]+(?=[^“”]*”)"

El [\ r \ n] + coincidirá con uno o más separadores de línea de cualquier tipo: Unix (\ n), DOS (\ r \ n) o Mac anterior (\ r) . Entonces el lookahead afirma que hay una cita cerrada por delante y que no hay una cita abierta entre aquí y allá. Entonces su texto de reemplazo puede ser un simple carácter de espacio.

Otros consejos

NB: Para la prueba de expresiones regulares, uso http://gskinner.com/RegExr/ que es muy útil.

No creo que puedas escribir una sola expresión que reemplace un número indefinido de nuevas líneas. Sin embargo, puede escribir una expresión para reemplazar una o varias, y ejecutarla repetidamente o escribirla para tratar el número máximo de nuevas líneas dentro de una sección citada.

Primero, desea el modo de línea única para que su expresión coincida con toda la cadena de entrada en lugar de línea por línea. Ponga esto al comienzo de su expresión para activarlo:

(?s)

Luego, desea que la expresión de búsqueda coincida con la cita de inicio:

(?<=“)

Y un avance para coincidir con la cita final:

(?=”)

Ahora una expresión para hacer coincidir un texto, luego una nueva línea, luego un texto:

([^”\r]*)\r?([^”\r]*)

Tenga en cuenta que hay dos grupos de captura para los bits de texto alrededor de la nueva línea, por lo que puede incluir ese texto en su expresión de reemplazo. Esto coincidirá con el texto que tiene solo una nueva línea dentro de las comillas. Para ampliar esto a dos nuevas líneas, solo agregue otra nueva línea opcional y el siguiente texto opcional:

(?s)(?<=“)([^”\r]*)\r?([^”\r]*)\r?([^”\r]*)(?=”)

Puede extender esto para que coincida con todas las nuevas líneas que crea que puedan ocurrir. No perfecto, pero quizás suficiente. O si puede ejecutar repetidamente la expresión en su texto, simplemente reemplace una por una.

Dejando tu expresión algo como esto:

r.Replace("(?s)(?<=“)([^”\r]*)\r?([^”\r]*)", "$1 $2")

(Esto no es del todo correcto, ya que agregará un espacio después del texto incluso si el grupo dos no coincide ... pero es un comienzo)

Entonces, lo que hay que hacer es encontrar una cadena que comience con una comilla de apertura, seguida de una cadena que no contenga una comilla de cierre o cualquier carácter \ r \ n, y que esté seguida de una serie de uno o más \ r \ n caracteres, captura todo menos los caracteres del terminal \ r \ n, y reemplaza toda la coincidencia con la porción capturada.

- MarkusQ

Creo que la forma más sencilla sería hacer coincidir las secciones citadas con & # 8220; (? s:. *?) & # 8221; y usar a MatchEvaluator para eliminar cualquier nueva línea. El código de MatchEvaluator podría ser tan simple como

Replace(@"\s+", " ");

Por supuesto, puede refinar esto para que coincida solo con las secciones citadas que realmente contienen nuevas líneas, y reemplazar solo las nuevas líneas dentro de esas secciones en lugar de todos los espacios en blanco, pero probablemente no valga la pena el esfuerzo.

No puede hacer lo que quiere dentro de los límites que ha descrito.

Prueba:

  • Su tabla fija de reemplazos ejecutará un número fijo de llamadas para reemplazar (llame a este n)
  • Cada reemplazo solo podrá eliminar un número fijo de saltos de línea (llame a este número m).

Por lo tanto

  • Un bloque entre comillas con m * n + 1 saltos de línea no se tratará adecuadamente.

Debe aumentar la potencia de su configuración (por ejemplo, permitiendo reemplazos más complejos, reemplazos recursivos, un indicador de repetición indefinido o ...?) o acepte el hecho de que su motor no puede realizar esta tarea .

- MarkusQ

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top