2008-12-25 10 views
7

Tengo un archivo que contiene varias líneas similares a:expresión regular para extraer pares de etiquetas de valor en Java

Name: Peter 
Address: St. Serrano número 12, España 
Country: Spain 

Y necesito para extraer la dirección usando una expresión regular, teniendo en cuenta que puede contener puntos , caracteres especiales (ñ, ç), áéíóú ...

El código actual funciona, pero se ve bastante feo :.

Pattern p = Pattern.compile("^(.+?)Address: ([a-zA-Z0-9ñÑçÇáéíóú., ]+)(.+?)$", 
          Pattern.MULTILINE | Pattern.DOTALL); 
Matcher m = p.matcher(content); 
if (m.matches()) { ... } 

Editar: El campo de dirección también podría ser dividida en múltiples líneas

Name: Peter 
Address: St. Serrano número 12, 
Madrid 
España 
Country: Spain 

Editar: No puedo utilizar un objeto Properties o un analizador YAML, ya que el archivo contiene otro tipo de información, también.

Respuesta

6

no sé objetos de expresiones regulares de Java que también, sino algo así como este patrón lo hará:

^Address:\s*((?:(?!^\w+:).)+)$ 

asumiendo varias líneas y dotall modos están activados.

Esto coincidirá con cualquier línea que comience por la dirección, seguida de cualquier elemento hasta un carácter de nueva línea y una sola palabra seguida de dos puntos.

si se conoce el siguiente campo tiene que ser "País", puede simplificar esto un poco:

^Address:\s*((?:(?!^Country:).)+)$ 

El truco está en la afirmación lookahead en el grupo de repetición. '(?!País:).' coincidirá con todo excepto con el inicio de la cadena 'País', por lo que solo lo pegaremos en paréntesis no capturables (?: ...) y lo cuantificaremos con +, luego agruparemos todo eso en el paréntesis de captura normal.

+0

¡Funcionó! Gracias ! Tengo que leer más sobre regex :) –

+0

Cualquiera leyendo esto. Para el caso de líneas múltiples, se debe pasar el indicador DOTALL y^y $ deben eliminarse del caso. –

0

No es una persona de Java, pero ¿no funcionaría un "Address: (.*)$"?

Edit: Without the Pattern.MULTILINE | La opción Pattern.DOTALL debe coincidir solo en esa línea.

0

¿Puede contener una nueva línea? Si no puede contener un carácter de nueva línea, que no es necesario utilizar el modificador de línea múltiple, y puede hacer en su lugar

Pattern p = Pattern.compile("^Address: (.*)$"); 

Si se puede, una alternativa que puedo pensar es

Pattern p = Pattern.compile("Address: (.*)\nCountry", Pattern.MULTILINE); 

Sin la dotall , el punto no coincidirá con una línea nueva, por lo que puede especificarlo explícitamente en la expresión regular, lo que le permite hacer lo que usted solicitó.

3

Es posible que desee buscar en la clase Properties en lugar de regex. Le proporciona formas de administrar texto sin formato o archivos XML para representar pares clave-valor.

Así se puede leer en el archivo de ejemplo y luego obtener los valores al igual que después de cargar a un objeto Properties:

Properties properties = new Properties(); 
properties.load(/* InputStream of your file */); 

Assert.assertEquals("Peter", properties.getProperty("Name")); 
Assert.assertEquals("St. Serrano número 12, España", properties.getProperty("Address")); 
Assert.assertEquals("Spain", properties.getProperty("Country")); 
+0

¿Por qué utilizar Apache Commons Assert isntead de Java assert? – cletus

0

Usted debería salir YAML.

Puede probar JYaml.

Lo mejor de todo es que tiene implementaciones en muchos idiomas.

ps He intentado con el texto de muestra en YAML::XS, y funciona perfectamente.

1

No me refiero a ser un palo en el barro, pero ¿tiene que usar una expresión regular? ¿Por qué no prescindir de su propio futuro (u otros) el dolor de cabeza y hacer:

String line = reader.readLine(); 
while(line != null) 
{ 
    line = line.trim(); 
    if(line.startsWith("Address: ")) 
    { 
     return line.substr("Address: ".length()).trim(); 
    } 
    line = reader.readLine(); 
} 
return null; 

Por supuesto, esto se puede parametrizar un poco así y puesto en un método.

De lo contrario, pondría en segundo lugar las sugerencias de Propiedades o JYaml.

3

Suponiendo que "contenido" es una cadena que contiene el contenido del archivo, su problema principal es que está usando matches() donde debe usar find().

Pattern p = Pattern.compile("^Address:\\s*(.*)$", Pattern.MULTILINE); 
Matcher m = p.matcher(content); 
if (m.find()) 
{ 
    ... 
} 

Parece haber cierta confusión en otras respuestas acerca de los modos MULTLINE y DOTALL. MULTILINE es lo que permite que los anclajes ^ y $ coincidan con el principio y el final, respectivamente, de una línea lógica. DOTALL permite que el punto (punto, punto final, lo que sea) coincida con los caracteres del separador de línea como \n (salto de línea) y \r (retorno de carro). Esta expresión regular debe usar el modo MULTILINE y no debe usar el modo DOTALL.

+0

Gracias. ¿Qué pasa si la dirección es un campo multilínea? ¿Es posible capturarlo sin necesidad de depender del siguiente nombre de campo? –

+0

Las dos expresiones regulares de Nick coincidirán si el campo Dirección está al final de la entrada. ¿Es eso lo que quieres decir? –

Cuestiones relacionadas