Rozdzielanie Stringa na tokeny z separatorami w tokenie

0

Witam

Temat może brzmi trochę zawile, ale tłumaczę o co chodzi. Mam plik tekstowy CSV, w którym separatorem może być znak przecinka albo średnika.

Posługując się metodą split (dla obiektu klasy String) potrafię rozdzielić napis na tokeny wg separatora np.

String tab[] = linia.split(separator);
for(int i = 0; i < tab.length(); i++)
   jTextArea1.append("Token nr " + Integer.toString(i) + " to: " + tab[i] +"\n");

Mój problem polega na tym, że w liniach (mam ich około 10 000 do przejścia) występują także linie postaci:

Kuchenki mikrofalowe;Zelmer;"Kuchenka mikrofalowa ZELMER;29Z;020";xxx;xx,x;xx

Chodzi o to, że separator występuje w tokenie, który został ograniczony cudzysłowami, podczas gdy metoda split "widzi" tylko znaki separatora i rozbija mi napis na osobne części:

"Kuchenka mikrofalowa ZELMER
29Z
020"

Czy istnieje może jakiś elegancki sposób żeby metoda split opuszczała szukanie separatora w napisach zawartych w cudzysłowach ?

Edit:

Napisałem kod, który to realizuje, ale jest on trochę zbyt przekombinowany:


int licznikCudz = 0;
for(int i = 0; i < tekst.length(); i++)
   if(tekst.charAt(i) == '"')
      licznikCudz++; // obliczam ilosc cudzysłowów w linii
if(licznikCudz == 0 || licznikC % 2 != 0)
   // takiej linii przerabiać nie będe
else {
   /* szukam wszystkich napisów ujętych w " */
   ArrayList<String> tokenyCudz = new ArrayList<String>();
   for(int i = 0; i < tekst.length(); i++) {
      if(tekst.charAt(i) == '"') { // " początkowy
         i++;
         String bufor = "";
         while(tekst.charAt(i) != '"') { // " końcowy
            bufor += tekst.charAt(i);
            i++;
         }
         tokenyCudz.add(bufor); // dodaje znaleziony napis
      }
   }

   /* rozdzielam linię znakiem " i tam gdzie znalazłem ciągi ujęte cudzysłowem, tam nie rozdzielam już separatorem */
   ArrayList<String> tokeny = new ArrayList<String>();
   String tablica[] = tekst.split("\""); // rozdzielam znakiem " całą linię
   for(int i = 0; i < tablica.length; i++) {
      if(tokenyCudz.size() > 0 && tablica[i].equals(tokenyCudz.get(0))) {
         tokeny.add(tablica[i]);
         tokenyCudz.remove(0); // usuwam pierwszy (tablica generyczna się aut. przesuwa w lewo)
      }
      else {
         String temp[] = tablica[i].split(separator);
         for(int j = 0 ; j < temp.length; j++)
            if(temp[j].length() > 0)
               tokeny.add(temp[j]);
      }
   }

   for(String token : tokeny)
      jTextArea1.append(token + "\n");
}
0

Moim zdaniem na splicie tego nie zrobisz
Zapoznaj się klasami Pattern i Matcher.
Tam możesz łączyć wyrażenia.
Przykłady znajdziesz na forum.

0
String s="Kuchenki mikrofalowe;Zelmer;\"Kuchenka mikrofalowa ZELMER;29Z;020\";xxx;xx,x;xx";
Pattern pattern = Pattern.compile("(^|\\G)([^\"]*?)(;|$)|\"(.*?)\"(;|$)");

Matcher matcher = pattern.matcher(s);
while(matcher.find()){
    String group = matcher.group(2); //przypadek bez cudzyslowow  ([^\"]*?)
    if (group == null){
        group = matcher.group(4);  //z cudzyslowami (.*?)
    }
    System.out.println(group);
}

Wynik:

Kuchenki mikrofalowe
Zelmer
Kuchenka mikrofalowa ZELMER;29Z;020
xxx
xx,x
xx
0

Dziękuje GhostDog i __krzysiek85. W szczególności za to wyrażenie regularne. Problem rozwiązany.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0