2009-06-12 13 views
5

¿Por qué .NET regex treat \ n como carácter de final de línea?Clase Regex de .NET y nueva línea

Código de ejemplo:

string[] words = new string[] { "ab1", "ab2\n", "ab3\n\n", "ab4\r", "ab5\r\n", "ab6\n\r" }; 
Regex regex = new Regex("^[a-z0-9]+$"); 
foreach (var word in words) 
{ 
    Console.WriteLine("{0} - {1}", word, regex.IsMatch(word)); 
} 

y esta es la respuesta que obtengo:

ab1 - True 
ab2 
- True 
ab3 

- False 
- False 
ab5 
- False 
ab6 
- False 

¿Por qué la coincidencia de expresiones regulares ab2\n?

Actualización: No creo Multiline es una buena solución, es decir, quiero validar inicio de sesión para que coincida con los caracteres especificados solamente, y debe ser de una sola línea. Si cambio el constructor para la opción MultiLine ab1, ab2, ab3 y ab6 coinciden con la expresión, ab4 y ab5 no coinciden.

+0

Por qué no muestra AB4 en la salida? –

+0

Supongo que es solo por el hecho de que es la salida exacta de la consola – empi

Respuesta

9

Si la cadena termina con un salto de línea, el RegexOptions.Multiline no funcionará. El $ simplemente ignorará el último salto de línea ya que no hay nada después de eso.

Si desea hacer coincidir hasta el final de la cadena y hacer caso omiso saltos de línea utilizan \z

Regex regex = new Regex(@"^[a-z0-9]+\z", RegexOptions.Multiline); 

Esto es para tanto MutliLine y SingleLine, eso no importa.

+0

Smazy, tienes razón. Me olvidé de los metacaracteres \ Z \ z (+1) –

+0

Funciona, pero ¿sabes si este enfoque puede causar otros problemas? ¿Cuál es la diferencia entre \ z y $? – empi

+0

\ z coincide solo con el final de la cadena, independientemente de las nuevas líneas –

1

De RegexOptions:

modo multilínea. Cambia el significado de^y $ para que coincidan al principio y al final, respectivamente, de cualquier línea, y no solo al principio y al final de la cadena completa.

Así que, básicamente, si pasa un RegexOptions.Multiline a la Regex constructor se están dando instrucciones esa instancia para tratar la final $ como a la altura de caracteres de nueva línea - no simplemente el final de la propia cadena.

+0

Por lo que yo entiendo, estoy especificando todos los caracteres que pueden aparecer en la cadena y estos caracteres son caracteres dentro del rango de [a-z0-9 ] No voy a permitir que \ n aparezca en la cadena, sin embargo, la expresión regular aún coincide con la cadena con \ n. No entiendo qué tiene que ver MultiLine con eso. – empi

0

Podrían ser las diferencias de terminación de la línea ususal windows/linux. Pero todavía es extraño que \n\n obtenga un falso de esta manera ... ¿Lo intentó con el indicador RegexOptions.Multiline establecido?

0

Solo para dar más detalles a la respuesta de Smazy. Este es un extracto de: Recetario de recetas regulares de Jan Goyvaerts y Steven Levithan. Copyright 2009 Ene Goyvaerts y Steven Levithan, 978-0-596-2068-7

La diferencia entre <\ Z> y <\ z> entra en juego cuando el último carácter en el texto objeto es un salto de línea de . En ese caso, <\ Z> puede coincidir al final del asunto texto, después del salto de línea final, como y justo antes de esa línea romper. La ventaja es que puede buscar sin tener que preocuparse por eliminar un salto de línea al final de su asunto texto.Al leer una línea de archivo por línea, algunas herramientas incluyen la línea ruptura al final de la línea, mientras que otros no; <\ Z> enmascara esta diferencia . <\ Z> coincide solo en el extremo del texto del asunto, por lo que no coincidirá con el texto si sigue una línea de seguimiento . El ancla <$> es equivalente a <\ Z>, siempre que lo haga no active la opción "^ y $ coincidir en la línea breaks". Esta opción está desactivada por por defecto para todos los sabores de expresiones regulares excepto Ruby. Ruby no ofrece una forma de desactivar esta opción. Al igual que <\ Z>, <$> coincide al final del texto del asunto , así como antes del salto de línea final , si corresponde.

Por supuesto, no lo habría encontrado sin la respuesta de Smazy.

10

El motor .NET regex trata \n como final de línea. Y eso es un problema si su cadena tiene saltos de línea \r\n al estilo Windows. Con RegexOptions.Multiline activado $ coincide entre \r y \n en lugar de antes de \r.

$ también coincide al final de la cadena al igual que \z. La diferencia es que \z solo puede coincidir al final de la cadena, mientras que $ también coincide antes de un \n final. Al usar RegexOptions.Multiline, $ también coincide antes que cualquier \n.

Si tiene problemas con los saltos de línea, un truco es buscar y reemplazar primero \r sin nada para asegurarse de que todas sus líneas terminen con \n solamente.

+2

Prefiero reemplazar "\ r \ n" por "\ n", por si acaso algún documento loco solo tiene alguna "\ r" por sí mismo como final de línea. – Jimmy

1

Use las opciones de expresiones regulares, System.Text.RegularExpressions.RegexOptions:

string[] words = new string[] { "ab1", "ab2\n", "ab3\n\n", "ab4\r", "ab5\r\n", "ab6\n\r" }; 
Regex regex = new Regex("^[a-z0-9]+$"); 
foreach (var word in words) 
{ 
    Console.WriteLine("{0} - {1}", word, 
     regex.IsMatch(word,"^[a-z0-9]+$", 
      System.Text.RegularExpressions.RegexOptions.Singleline | 
      System.Text.RegularExpressions.RegexOptions.IgnoreCase | 
      System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace)); 
}