2016-03-07 20 views
8

muszę podzielić ciąg używając przecinek (,) jako separatora i ignoruje wszelkie przecinek, który jest cytaty wewnątrz (")
Java: Dzielenie String przy użyciu regex

fieldSeparator : ,
fieldGrouper : "

Łańcuch do rozłamu jest: "1","2",3,"4,5"

jestem w stanie to osiągnąć w następujący sposób:

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

wyjściowa:

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

Teraz wyzwaniem jest to, że fieldGrouper (") nie powinny być częścią tokenów dzielonych. Nie jestem w stanie znaleźć w tym celu wyrażenia regularnego.

Oczekiwany wyjście podziału jest:

1 
2 
3 
4,5 
+0

myślę, że robi to char-by-char będzie bardziej czytelny i zdecydowanie szybszy. Algorytm jest tak prosty, jak to tylko możliwe. I łatwiej jest obsłużyć wyjątek '' "', który prawdopodobnie pojawi się prędzej czy później. – Dariusz

+0

Czy możemy zapytać, dlaczego pracujesz ze zniekształconym wejściem pseudo JSON? Ożywienie z cytatami sprawia, że ​​trudno się z tym uporać i może być lepiej dla ciebie, aby oczyścić źródło. –

Odpowiedz

4

Aktualizacja:

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

Wynik:
Image Link

Początkowa Rozwiązanie:
(nie działa @.split metody)

Ten RexEx wzór będzie izolować sekcje chcesz:
(?:\\")(.*?)(?:\\")

Wykorzystuje zakaz robienia grup do izolowania pary escaped quotes, i grupa przechwytująca, aby odizolować wszystko pomiędzy.

Sprawdź to tutaj: Live Demo

+2

To wyrażenie nie pasuje do '3' lub żadnych innych wartości nie zawartych w' "..." '. –

+0

@ WiktorStribiżew Zaktualizowałem rozwiązanie, ale w moim początkowym rozwiązaniu założyłem, że wzór "#" jest spójny. Nie zdawałem sobie sprawy, że '3' nie został przechwycony i nadal zastanawiam się, czy @rvd celowo ma inny format dla' 3'. Tak czy inaczej, nowe rozwiązanie działa. – Enteleform

+0

Przepraszam, ale twoje drugie rozwiązanie nie będzie działało jako wejście, np. 1,2, gdy 1 i 2 są oddzielnymi liczbami. –

0

Moja propozycja:

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

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

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

Moja sugestia:

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

Patrz regex demo. Będzie pasował do "..." jak ciągi i przechwytuje do grupy 1 tylko to, co jest pomiędzy cytatami, a następnie dopasuje i przechwyci do sekwencji Grupy 2 znaków innych niż , na początku łańcucha lub po przecinku.

Oto 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

Lepszą sugestią jest, aby wyczyścił swoje dane źródłowe IMHO. –

1

chciałbym spróbować z tego rodzaju rozwiązania:

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

wyjściowa:

1 
2 
3 
4,5 
+0

W końcu musiałem użyć podobnego rozwiązania, tj. Najpierw podzielić, a następnie usunąć cytaty (jeśli są obecne) z każdego tokena. – rvd