2009-07-29 9 views
6

Come si analizza il seguente String utilizzando Java per estrarre il percorso del file?Che cos'è un modo efficiente per analizzare una stringa in Java?

? indica qualsiasi numero di charaters casuali

_ indica qualsiasi numero di spazi bianchi (senza nuova linea)

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

Esempio:

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

dovrebbe estrarre foo/bar/baz.xml

risposta

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); 

Il risultato di String dovrebbe essere il percorso del file. (presupponendo di non aver commesso errori)

Si dovrebbe dare un'occhiata alla classe Pattern per alcuni aiuti di espressioni regolari. Possono essere uno strumento di manipolazione delle stringhe molto potente.

+0

". * \\ [LoadFile \\] \\ s * file \\ s * = \\ s * \" ([^ \\\ "]. *) \". * "Sarebbe meglio abbinare qualsiasi numero di spazi bianchi – Jean

+1

". * \" ([^ \\\ "]. *) \". * "sarebbe ancora meglio dato che non ci interessa affatto il formato del prefisso (noto per impostazione predefinita) e non contiene qualsiasi citazione. – gizmo

+0

FYI, la regex di Jean non corrisponderebbe allo spazio bianco, es. [LoadFile] file = "foo/bar/baz.xml". Quindi se vuoi almeno un carattere di spazio bianco, usa + invece di * come jinguy originariamente specificato. –

1

java.util.regex è tuo amico.

+1

Questo è solo leggermente utile – jjnguy

+4

Alcune persone, di fronte a una domanda di Overflow dello stack, rispondono "java.util.regex è tuo amico" Ora la persona che pone la domanda ha due problemi. (Liberalmente parafrasato da http://blogs.msdn.com/oldnewthing/archive/2006/03/22/558007.aspx) - Se hai intenzione di suggerire di utilizzare espressioni regolari, fornisci un esempio. –

+1

@Grant Wagner Non vedo nulla di sbagliato nel dirigere le persone nella giusta direzione, anche se non ho il tempo di elaborare una soluzione completa. Se non sei soddisfatto della risposta, allora dai una migliore, invece di perdere tempo a lamentarti. – starblue

1

Si potrebbe rendere l'espressione regolare un po 'più breve di quella di jinguy. In pratica solo il RHS senza la "s '.

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

penso che jinguy abbia presupposto che il percorso debba essere estratto solo se la riga ha [LoadFile] in esso ... – Jean

+0

Quando scrivo un'espressione regolare, cerco di essere il più specifico possibile. – jjnguy

2

Mentre le espressioni regolari sono bello e tutto, si può anche utilizzare classe java.util.StringTokenizer per fare il lavoro. Il vantaggio è un codice più umano-friendly.

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

E ci si va

+0

Un altro vantaggio di StringTokenizer è che probabilmente sarà più efficiente ... a condizione che sia in grado di svolgere il lavoro a portata di mano. –

+0

È solo che se ci sono un certo numero di "caratteri nel primo set di caratteri casuali, il tokenizzatore tornerà felicemente come elemento successivo, ma l'esempio suggerisce che la prima parte della riga di input è solo un timestamp." Una regex è più difficile da scrivere, ma molto più capace di gestire input molto diversi –

+0

Sono d'accordo sul fatto che un StringTokenizer non è la soluzione ideale per ogni problema di parsing, ma in questo caso mi sembra davvero che usare una regex sia un po ' come la caccia alle mosche con un cannone ... – Yuval

3

risposta breve:.. utilizzare sottosequenza()

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

Sulla mia macchina, questo richiede sempre meno di 10.000 ns.

Sto prendendo "efficiente" per significare più veloce.

L'opzione gee è notevolmente più lenta (circa 9 o 10 volte più lenta). Il vantaggio principale dell'opzione regex è che potrebbe essere più semplice per un altro programmatore capire cosa stai facendo (ma poi usare i commenti per aiutarli).

Per rendere l'opzione regex più efficiente, pre-compilarlo:

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

Ma questo lascia ancora più lento. Registro i tempi tra 80.000 e 100.000 ns.

L'opzione StringTokenizer è più efficiente rispetto alla regex:

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

Questo si aggira intorno 40.000 ns per me, mettendolo in a 2-3 volte più veloce rispetto l'espressione regolare.

In questo scenario, split() è anche un'opzione, che per me (utilizzando Java 6_13) è solo un po 'più veloce rispetto al Tokenizer:

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

Questo medie tempi di 35.000 ns per me.

Ovviamente, nessuno di questi controlla errori. Ogni opzione diventerà un po 'più lenta quando inizi a scomporla, ma penso che l'opzione subSequnce() continuerà a batterli tutti. Devi conoscere i parametri esatti e le aspettative per capire come deve essere tollerante ogni opzione.

Problemi correlati