Espressioni regolari per coppie estratto etichetta di valore in Java
-
23-08-2019 - |
Domanda
Ho un file che contiene diverse linee simili a:
Name: Peter
Address: St. Serrano número 12, España
Country: Spain
E ho bisogno di estrarre l'indirizzo utilizzando un'espressione regolare, tenendo conto che essa può contenere punti, caratteri speciali (ñ, ç), AEIOU ...
Il codice attuale funziona, ma sembra abbastanza brutto:.
Pattern p = Pattern.compile("^(.+?)Address: ([a-zA-Z0-9ñÑçÇáéíóú., ]+)(.+?)$",
Pattern.MULTILINE | Pattern.DOTALL);
Matcher m = p.matcher(content);
if (m.matches()) { ... }
Modifica: Il campo Indirizzo potrebbe anche essere diviso in più righe
Name: Peter
Address: St. Serrano número 12,
Madrid
España
Country: Spain
Modifica:. Non posso usare un oggetto o di proprietà di un parser YAML, come il file contiene altri tipi di informazioni, anche
Soluzione
Non so oggetti regex di Java che bene, ma qualcosa di simile modello lo farò:
^Address:\s*((?:(?!^\w+:).)+)$
assumendo modalità multilinea e dotall sono.
Questa corrisponderà a qualsiasi riga che inizia con Indirizzo, seguita da nulla fino a quando un carattere di nuova riga e una sola parola seguito da due punti.
Se si conosce il campo successivo deve essere "Paese", è possibile semplificare questo un po ':
^Address:\s*((?:(?!^Country:).)+)$
Il trucco sta nel asserzione che guarda avanti nel gruppo ripetuto. '(?!Nazione:).' corrisponderà tutto tranne l'inizio della stringa 'Paese:', quindi abbiamo solo bastone in non cattura parentesi (:? ...). e quantificare con +, poi gruppo tutto questo in normali parentesi di cattura
Altri suggerimenti
Si potrebbe voler guardare in Properties
classe invece di regex. Esso fornisce il modo di gestire i file di testo o XML semplici per rappresentare coppie chiave-valore.
Così si può leggere nel file di esempio e quindi ottenere i valori in questo modo dopo il caricamento di un oggetto 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"));
Supponendo "contenuto" è una stringa contenente il contenuto del file, il problema principale è che si sta utilizzando matches()
dove si dovrebbe usare find()
.
Pattern p = Pattern.compile("^Address:\\s*(.*)$", Pattern.MULTILINE);
Matcher m = p.matcher(content);
if ( m.find() )
{
...
}
Sembra che ci sia una certa confusione in altre risposte sulle modalità multline e dotall. MULTILINE è ciò che permette le ancore ^
e $
corrispondono all'inizio e alla fine, rispettivamente di una linea logica. DOTALL lascia il punto (periodo, punto e basta, a prescindere) linea partita caratteri separatori come \n
(avanzamento riga) e \r
(ritorno a capo). Questa espressione regolare deve modalità di utilizzo MULTILINE e non deve Modalità uso DOTALL.
Non voglio dire di essere un bastone nel fango, ma non è necessario utilizzare una regex? Perché non risparmiare il vostro sé futuro (o altri) il mal di testa e fare:
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;
Naturalmente questo può essere parametrizzata un po 'come bene e messo in un metodo.
In caso contrario, mi piacerebbe secondo le proprietà o JYaml suggerimenti.
Non una persona di Java, ma non sarebbe un'opera "Address: (.*)$"
?
Modifica: Senza il Pattern.MULTILINE | opzione Pattern.DOTALL dovrebbe corrispondere solo su quella linea.
Può contenere una nuova linea? Se non riesce a contenere un ritorno a capo, non è necessario utilizzare il modificatore multilinea, e può fare al posto
Pattern p = Pattern.compile("^Address: (.*)$");
Se è possibile, in alternativa mi viene in mente è
Pattern p = Pattern.compile("Address: (.*)\nCountry", Pattern.MULTILINE);
Senza la DOTALL, il punto sarà non corrisponde un ritorno a capo, in modo da poter specificare esplicitamente nella regexp, che consente di fare quello che hai chiesto.
Si dovrebbe verificare YAML .
Si potrebbe provare a JYaml .
Il meglio di tutto ciò che ha implementazioni in molte lingue.
ps Ho provato il testo di esempio nel YAML :: XS , e funziona perfettamente.