2010-08-10 29 views
15

Actualmente estoy tratando de aprender a usar expresiones regulares así que tenga paciencia con mi pregunta simple. Por ejemplo, decir que tengo un archivo de entrada que contiene un montón de enlaces separados por un salto de línea:RegEx en Java: cómo lidiar con newline

www.foo.com/Archives/monkeys.htm
Descripción de la página web del mono.

www.foo.com/Archives/pigs.txt
Descripción del sitio web de Pig.

www.foo.com/Archives/kitty.txt
Descripción del sitio web de Kitty.

www.foo.com/Archives/apple.htm
Descripción del sitio web de Apple.

Si quería conseguir un sitio web junto con su descripción, esta expresión regular parece funcionar en una herramienta de prueba: .*www.*\\s.*Pig.*

Sin embargo, cuando intento ejecutarlo dentro de mi código no parece funcionar . Es esta expresión correcta? Intenté reemplazar "\ s" con "\ n" y parece que todavía no funciona.

Respuesta

0

Obras para mí:

import java.util.regex.Pattern; 
import java.util.regex.Matcher; 
public class Foo { 
    public static void main(String args[]) { 
    Pattern p = Pattern.compile(".*www.*\\s.*Pig.*"); 
    String s = "www.foo.com/Archives/monkeys.htm\n" 
      + "Description of Monkey's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/pigs.txt\n" 
      + "Description of Pig's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/kitty.txt\n" 
      + "Description of Kitty's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/apple.htm\n" 
      + "Description of Apple's website.\n"; 
    Matcher m = p.matcher(s); 
    if (m.find()) { 
     System.out.println(m.group()); 
    } else { 
     System.out.println("ERR: no match"); 
    } 
    } 
} 

Tal vez el problema era con la forma en que estaba utilizando el modelo objetos y Matcher?

+1

Esto solo funciona si las líneas siempre se formatean con \ n, ya que en unix – Gary

32

Las líneas probablemente están separadas por \r\n en su archivo. Tanto \r (retorno de carro) como \n (avance de línea) se consideran caracteres separadores de líneas en expresiones regulares de Java, y el metacaracter de . no coincidirá con ninguno de ellos. \s coincidirá con esos caracteres, por lo que consume el \r, pero eso deja .* para que coincida con el \n, que falla. Su probador probablemente usó solo \n para separar las líneas, que fue consumido por \s.

Si estoy en lo cierto, al cambiar \s a \s+ o [\r\n]+ debería hacerlo funcionar. Probablemente sea todo lo que tiene que hacer en este caso, pero a veces tiene que coincidir exactamente con un separador de línea o, al menos, hacer un seguimiento de la cantidad de coincidencias. En ese caso, necesita una expresión regular que coincida exactamente con uno de los tres tipos de separador de línea más comunes: \r\n (Windows/DOS), \n (Unix/Linus/OSX) y \r (Mac antiguos). Cualquiera de estos hacer:

\r\n|[\r\n] 

\r\n|\n|\r 

Actualización: A partir de Java 8 tenemos otra opción, \R. Coincide con cualquier separador de línea, incluidos no solo \r\n, sino varios más, tal como se define en Unicode standard.Es equivalente a esto:

\r\n|[\n\x0B\x0C\r\u0085\u2028\u2029] 

Así es como usted puede utilizarlo:

(?im)^.*www.*\R.*Pig.*$ 

La opción i hace que sea sensible a las mayúsculas y la m lo pone en modo multilínea, permitiendo ^ y $ para que coincida en los límites de la línea.

0

Esta versión coincide con saltos de línea que pueden ser ya sea de Windows (\ r \ n) o Unix (\ n)

Pattern p = Pattern.compile("(www.*)((\r\n)|(\n))(.*Pig.*)"); 
String s = "www.foo.com/Archives/monkeys.htm\n" 
      + "Description of Monkey's website.\n" 
      + "\r\n" 
      + "www.foo.com/Archives/pigs.txt\r\n" 
      + "Description of Pig's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/kitty.txt\n" 
      + "Description of Kitty's website.\n" 
      + "\n" 
      + "www.foo.com/Archives/apple.htm\n" 
      + "Description of Apple's website.\n"; 
Matcher m = p.matcher(s); 
if (m.find()) { 
    System.out.println("found: "+m.group()); 
    System.out.println("website: "+m.group(1)); 
    System.out.println("description: "+m.group(5)); 
} 
System.out.println("done"); 
9

Para referencia futura, también se puede utilizar el Indicador Pattern.DOTALL para "." para emparejar incluso \ r o \ n.

Ejemplo:

Diga el que estamos analizar una sola cadena de líneas de cabecera HTTP como esto (cada línea terminó con \ r \ n)

HTTP/1.1 302 Found 
Server: Apache-Coyote/1.1 
Cache-Control: no-cache, no-store, max-age=0, must-revalidate 
Pragma: no-cache 
Expires: 0 
X-Frame-Options: SAMEORIGIN 
Location: http://localhost:8080/blah.htm 
Content-Length: 0 

Este patrón:

final static Pattern PATTERN_LOCATION = Pattern.compile(".*?Location\\: (.*?)\\r.*?", Pattern.DOTALL); 

Puede analizar el valor de ubicación usando "matcher.group (1)".

El "." en el patrón anterior coincidirá con \ r y \ n, por lo que el patrón anterior puede analizar la "Ubicación" de las líneas de encabezado http, donde puede haber otros encabezados antes o después de la línea objetivo (no es que esta sea una manera recomendada de analizar encabezados http).

Además, puede usar "? S dentro del patrón para lograr el mismo efecto.

Si está haciendo esto, es mejor que utilice Matcher.find().

+0

DOTALL no es realmente útil en este caso. El OP necesita saber cuándo la expresión regular consume el separador de línea para asegurarse de que solo está haciendo coincidir uno de ellos. Y es aún menos útil en su ejemplo, donde todo el contenido de interés está contenido en una línea. Casi nunca uso el modo DOTALL; parece causar más problemas de los que resuelve. –

+0

Probablemente tengas razón, pero es útil en mi ejemplo, sin embargo, mi secuencia única para analizar realmente tenía todas las líneas. – javaPhobic

+0

Lo que pasa con el modo DOTALL es que amplía enormemente el alcance de las travesuras. Por ejemplo, cuando aplico su expresión regular a sus datos de muestra, el primer '. *?' Consume todos los encabezados que se enumeran arriba del encabezado 'Ubicación'. Sé que solo te importa la URL que estás capturando en el grupo n. ° 1, pero igual la obtendrás con el modo DOTALL desactivado, y ahorrarás mucho trabajo innecesario para la expresión regular. –