2016-03-07 14 views
8

devo dividere una stringa utilizzando virgola (,) come separatore e ignorare qualsiasi virgola che si trova tra virgolette (")
Java: suddivisione di un testo utilizzando Regex

fieldSeparator : ,
fieldGrouper : "

La stringa a Spalato è: "1","2",3,"4,5"

sono in grado di realizzarlo nel modo seguente:

String record = "\"1\",\"2\",3,\"4,5\""; 
String[] tokens = record.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"); 

uscita:

"1" 
"2" 
3 
"4,5" 

Ora la sfida è che il fieldGrouper (") non dovrebbe essere una parte dei token di divisione. Non riesco a capire la regex per questo.

L'uscita prevista della divisione è:

1 
2 
3 
4,5 
+0

Penso che facendo questo char-by-char sarà effettivamente più leggibile e sicuramente più veloce. E l'algoritmo è tanto semplice quanto diventa. Ed è più facile gestire l'eccezione "" "che probabilmente verrà visualizzata prima o poi. – Dariusz

+0

Possiamo chiederti perché stai lavorando con input Pseudo JSON non valido? Il funky con le virgolette rende questo difficile da gestire e potrebbe essere meglio per voi per ripulire la fonte. –

risposta

4

Aggiornamento:

String[] tokens = record.split("(,*\",*\"*)");

Risultato:
Image Link

iniziale Soluzione:
(non funziona @.split metodo)

Questa RexEx modello isolerà le sezioni che si desidera:
(?:\\")(.*?)(?:\\")

Usa non cattura i gruppi per isolare le coppie di citazioni sfuggite, e un gruppo che cattura per isolare tutto nel mezzo.

verificarlo qui: Live Demo

+2

Questa espressione regolare non corrisponde a '3' o altri valori non inclusi in' "..." '. –

+0

@ WiktorStribiżew Ho aggiornato la soluzione, ma nella mia soluzione iniziale ho pensato che il modello "#" era coerente. Non mi sono reso conto che '3' non è stato catturato, e mi chiedo ancora se @rvd abbia di proposito un formato diverso per' 3'. Ad ogni modo, la nuova soluzione funziona. – Enteleform

+0

Scusa ma la tua seconda soluzione non funzionerà per input come 1,2 quando 1 e 2 sono numeri separati. –

0

mia proposta:

record = record.replaceAll("\",", "|"); 
record = record.replaceAll(",\\\"", "|"); 
record = record.replaceAll("\"", ""); 

String[] tokens = record.split("\\|"); 

for (String token : tokens) { 
    System.out.println(token); 
} 
2

Il mio suggerimento:

"([^"]+)"|(?<=,|^)([^,]*) 

Vedere le regex demo. Corrisponde a "..." come stringhe e cattura nel Gruppo 1 solo ciò che è tra le virgolette e quindi corrisponderà e catturerà in sequenze di caratteri del gruppo 2 diverse da , all'inizio di una stringa o dopo una virgola.

Ecco un Java sample code:

String s = "value1,\"1\",\"2\",3,\"4,5\",value2"; 
Pattern pattern = Pattern.compile("\"([^\"]+)\"|(?<=,|^)([^,]*)"); 
Matcher matcher = pattern.matcher(s); 
List<String> res = new ArrayList<String>(); 
while (matcher.find()){      // Run the matcher 
    if (matcher.group(1) != null) {   // If Group 1 matched 
     res.add(matcher.group(1));   // Add it to the resulting array 
    } else { 
     res.add(matcher.group(2));   // Add Group 2 as it got matched 
    } 
} 
System.out.println(res); // => [value1, 1, 2, 3, 4,5, value2] 
+0

Il suggerimento migliore è che pulisca i suoi dati di origine IMHO. –

1

vorrei provare con questo tipo di soluzione:

String record = "\"1\",\"2\",3,\"4,5\""; 
record = record.replaceAll("\"?(?<!\"\\w{1,9999}),\"?|\""," "); 
String[] tokens = record.trim().split(" "); 
for(String str : tokens){ 
    System.out.println(str); 
} 

uscita:

1 
2 
3 
4,5 
+0

Alla fine ho dovuto ricorrere a una soluzione alternativa, vale a dire, prima dividere e quindi rimuovere le virgolette (se presenti) da ciascun token. – rvd