2009-07-29 12 views
6

¿Cómo debo analizar el siguiente String usando Java para extraer la ruta del archivo?¿Cuál es una forma eficiente de analizar una cadena en Java?

? significa cualquier número de charaters aleatorios

_ significa cualquier número de espacios en blanco (sin nueva línea)

?[LoadFile]_file_=_"foo/bar/baz.xml"? 

Ejemplo:

10:52:21.212 [LoadFile] file = "foo/bar/baz.xml" 

debe extraer foo/bar/baz.xml

Respuesta

12
String regex = ".*\\[LoadFile\\]\\s+file\\s+=\\s+\"([^\"].+)\".*"; 

Matcher m = Pattern.compile(regex).matcher(inputString); 
if (!m.find()) 
    System.out.println("No match found."); 
else 
    String result = m.group(1); 

El String en el resultado debe ser su ruta de archivo. (suponiendo que no cometí ningún error)

Debería echar un vistazo a la clase Pattern para obtener ayuda con la expresión regular. Pueden ser una herramienta de manipulación de cadenas muy poderosa.

+0

". * \\ [LoadFile \\] \\ s * file \\ s * = \\ s * \" ([^ \\\ "]. *) \". * "Sería mejor hacer coincidir cualquier número de espacios en blanco – Jean

+1

". * \" ([^ \\\ "]] *) \". * "sería aún mejor ya que no nos importa el formato de prefijo en absoluto (conocido por defecto) y no contiene cualquier cita. – gizmo

+0

FYI, la expresión regular de Jean tampoco coincidiría con el espacio en blanco, ej. [LoadFile] file = "foo/bar/baz.xml". Por lo tanto, si desea al menos un carácter de espacio en blanco, use + en lugar de * como jinguy originalmente especificado. –

1

java.util.regex es tu amigo.

+1

Eso es sólo ligeramente útil – jjnguy

+4

Algunas personas, cuando se enfrentan a una pregunta de desbordamiento de pila, respuesta "java.util.regex es su amigo" Ahora, la persona que hace la pregunta tiene dos problemas. (Parafraseado liberalmente de http://blogs.msdn.com/oldnewthing/archive/2006/03/22/558007.aspx) - Si va a sugerir el uso de expresiones regulares, proporcione un ejemplo. –

+1

@Grant Wagner No veo nada de malo en señalar a las personas en la dirección correcta, incluso si no tengo tiempo para encontrar una solución completa. Si no está contento con la respuesta, entonces dé una mejor en lugar de perder el tiempo quejándose. – starblue

1

Puede hacer que la expresión regular sea un poco más corta que la de jinguy. Básicamente, sólo el lado derecho sin el "'s.

String regex = ".* = \"(.*)\""; 
+0

creo jinguy supone que el camino sólo debe ser extraída si la línea tiene [LoadFile] en ella ... – Jean

+0

Cuando escribo una expresión regular, trato de ser lo más específico posible. – jjnguy

2

Mientras que las expresiones regulares son agradables y todo, también puede utilizar la clase java.util.StringTokenizer para hacer el trabajo. La ventaja es un código más humana de usar.

StringTokenizer tokenizer = new StringTokenizer(inputString, "\""); 
tokenizer.nextElement(); 
String path = tokenizer.nextElement(); 

Y hay que ir

+0

Otra ventaja de StringTokenizer es que probablemente sea más eficiente ... siempre que sea capaz de hacer el trabajo que tiene entre manos. –

+0

Es que si sucede que hay una serie de "personajes de la primera serie de caracteres aleatorios del tokenizer volverá felizmente que a medida que el siguiente elemento. Sin embargo, el ejemplo sugiere la primera parte de la línea de entrada es sólo una marca de tiempo. una expresión regular es más difícil de escribir, pero mucho más capaz de manejar de entrada muy diferentes. –

+0

Estoy de acuerdo que un StringTokenizer no es una solución ideal para todos los problemas de análisis, pero en este caso lo que realmente me parece que el uso de una expresión regular es un poco como cazar moscas con un cañón ... – Yuval

3

respuesta corta:.. utilizar subsecuencia()

if (line.contains("[LoadFile]")) 
    result = line.subSequence(line.indexOf('"'), line.lastIndexOf('"')).toString(); 

En mi máquina, esto siempre requiere menos de 10,000 ns.

Estoy tomando "eficiente" para significar más rápido.

La opción regex es considerablemente más lenta (aproximadamente 9 o 10 veces más lenta). La principal ventaja de la opción de expresión regular es que podría ser más fácil para otro programador averiguar lo que está haciendo (pero luego usar comentarios para ayudarlos).

que la opción más eficiente de expresiones regulares, pre-compilarlo:

private static final String FILE_REGEX = ".*\\[LoadFile\\]\\s+file\\s+=\\s+\"([^\"].+)\".*"; 
private static final Pattern FILE_PATTERN = Pattern.compile(FILE_REGEX); 

Pero esto todavía deja más lento. Grabo tiempos entre 80,000 y 100,000 ns.

La opción StringTokenizer es más eficiente que la expresión regular:

if (line.contains("[LoadFile]")) { 
    StringTokenizer tokenizer = new StringTokenizer(line, "\""); 
    tokenizer.nextToken(); 
    result = tokenizer.nextToken(); 
} 

Esta ronda los 40.000 ns para mí, poniéndolo en al 2-3 veces más rápido que la expresión regular.

En este escenario, split() también es una opción, que para mí (usando Java 6_13) es sólo un poco más rápido que el Tokenizer:

if (line.contains("[LoadFile]")) { 
    String[] values = line.split("\""); 
    result = values[1]; 
} 

Esto da un promedio de 35.000 veces ns para mí.

Por supuesto, nada de esto es la comprobación de errores. Cada opción se volverá un poco más lenta cuando empieces a factorizar eso, pero creo que la opción subSequnce() aún los superará a todos. Debe conocer los parámetros exactos y las expectativas para determinar cuán tolerante a fallas debe ser cada opción.

Cuestiones relacionadas