2010-11-22 18 views
5

Estoy tratando de usar expresiones regulares de Java para que coincida con un patrón que abarca varias líneas. El patrón tiene una línea que comienza con 'A' seguido de exactamente 50 caracteres y luego una o más líneas que comienzan con 'B' seguido de exactamente 50 caracteres:Expresión regular de Java para buscar varias líneas de una longitud específica

A... // exactly 50 chars after the A 
B... 
B... 

no parecen Java expresiones regulares para apoyar esto sin embargo.

Aquí es una expresión regular que funciona para una A y una línea B:

A.{50}[\\n[\\n\\r]]B.{50}[\\n[\\n\\r]] 

aquí es la misma expresión regular modificado para encontrar una o más líneas B:

A.{50}[\\n[\\n\\r]][B.{50}[\\n[\\n\\r]]]+ 

Esta expresión regular sólo encuentra el personaje principal B en la primera línea B, sin embargo.

Utilizo [\\n[\\r\\n]] para manejar nuevas líneas de DOS y UNIX. Activar el modo MULTILINE no afecta los resultados.

El problema parece ser cuando uso los corchetes con '+' para convertir la expresión regular de una línea B en una clase de caracteres que puede capturar varias líneas.

¿Hay algo sobre expresiones regulares de Java que no permita el '.' carácter o los corchetes para especificar una longitud de línea exacta?

+0

Hay una línea A con 50 caracteres siguiendo la 'A', luego varias líneas B con 50 caracteres siguiendo la 'B' inicial. stackoverflow no conservó las líneas nuevas entre las líneas A y B que mostré arriba. –

Respuesta

0

En la siguiente expresión regular:

(A[^\r\n]{50}(\r\n|\n))(B[^\r\n]{50}(\r\n|\n))+ 

que utilizan [^\r\n] para que coincida con cualquier carácter que no es \r o \n. Puede reemplazarlo con [\d] si tiene dígitos, por ejemplo.

Ver http://www.myregextester.com/?r=b7c3ca56

En el ejemplo, la expresión regular coincide con todos excepto la última línea.

+0

Eso parece funcionar. –

0

para manejar tanto Unix y nueva línea de estilo Dos se pueden utilizar:

\\r?\\n 

También su forma de agrupar uno o más B líneas es incorrecto, está utilizando [] para agrupar, usted debe utilizar (?: ) lugar.

probar este regex:

A.{50}\\r?\\n(?:B.{50}(?:\\r?\\n)?)+ 

Regex tested here

+0

Solo por el hecho de que publicaste una versión de ruby. Aquí hay una gran versión de python de un probador de expresiones regulares http://www.pythonregex.com/ – Falmarri

+0

Gracias. Eso parece funcionar. –

0

Esto debería funcionar:

String input = "A1234567890\nA12345678\nA12345678\nB12345678\nA123456\nA1234567\nZA12345678\nB12345678\nA12345678\nB12345678\nB12345678\nB12345678\nB1234567\nA12345678\nB12345678"; 

String regex = "^A.{8}$((\\r|\\r\\n|\\n)^B.{8}$)+(\\r|\\r\\n|\\n|\\z)"; 

Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); 
Matcher matcher = pattern.matcher(input); 

while (matcher.find()) { 
System.out.println("matches from " + matcher.start() + " to " + matcher.end()); 
} 

Nota:

  1. el uso de ^, $ y MULTILINE para evitar que coincidan con la línea que comienza con "ZA".
  2. el uso de (\\r|\\r\\n|\\n) para que coincida con Unix, Windows y viejas líneas de mac-os.
  3. el uso de (\\r|\\r\\n|\\n|\\z) para que coincida con la última línea B sin un final de línea

Opsss, solía 8 en lugar de 50 para aumentar la legibilidad.

+0

Debe ser 10 en lugar de 8. –

+0

No, la primera línea es una muestra de la línea que no coincide. – andcoz

0

El punto y las llaves funcionan bien; es el resto de tu expresión regular lo que está mal. Mira esto:

Pattern p = Pattern.compile("^A.{50}(?:(?:\r\n|[\r\n])B.{50})+$"); 

(?:\r\n|[\r\n]) detecta una secuencia CRLF, CR solamente, o solamente LF. (Podría haber usado dos barras diagonales inversas como las que hizo, pero esto también funciona).

Si utiliza la expresión regular para arrancar partidos de algún texto más grande, tendrá que compilarlo en modo multi-modo que los ^ y $ anclas pueden igualar en los límites de la línea. Si se supone que debe coincidir con una cadena completa, déjelo en el modo predeterminado para que solo coincidan al principio y al final de la cadena.

0

La forma correcta para que coincida con una secuencia de salto de línea es:

"(?:(?>\\u000D\\u000A)|[\\u000A\\u000B\\u000C\\u000D\\u0085\\u2028\\u2029)" 

Eso es en notación cadena slackbashy de Java, por supuesto, del mismo modo que se puede desmayar a Pattern.compile. Más idiomas razonables le permiten llegar a funcionar con simplemente esto:

(?:(?>\x0D\x0A)|\v) 

Pero entonces, expresiones regulares de Java no han sido nunca nada parecido razonable, e incluso esto es en realidad un eufemismo para how bad they really are. El poor support for whitespace detection de Java es solo uno de los innumerables puntos problemáticos de sus expresiones regulares.

Buena suerte: la necesitarás. ☹

0

Esto debería funcionar también:

Pattern regex = Pattern.compile("^A.{50}$\\s+(?:^B.{50}$\\s*)+(?:^|\\z)", Pattern.MULTILINE); 

El razonamiento detrás de esto es que ^ partidos en el inicio de la línea, $ partidos al final de la línea, antes de que una (opcional) carácter de nueva línea, y \s coincide con el espacio en blanco que incluye \r y \n. Dado que lo estamos utilizando entre $ y ^, solo puede coincidir con caracteres de nueva línea y no con otros espacios en blanco.

El (?:^|\\z) se utiliza para garantizar que no coincidamos accidentalmente con ningún espacio inicial en la línea que sigue a la última repetición de la línea B. Si las líneas nunca comienzan con espacios en blanco, puede soltar este bit.

Cuestiones relacionadas