[JAVA] [RegExp] Problem z przecinkami i cudzysłowami

0

Witam,

Męczę się już trochę nad tym (w zasadzie nie mam doświadczenia z regexpami, bo dopiero staram się je zgłębić) i niestety nie mogę poradzić sobie z następującym przykładem. Proszę o pomoc/wskazówki.

Mamy ciąg wyrazów oddzielonych przecinkami, ale niektóre z nich mogą być ujęte w cudzysłowy (wtedy przecinki wewnątrz nich nie dzielą słowa na dwie części). Do tego w słowie (niekoniecznie tym ujętym w cudzysłowy) może wystąpić znak cudzysłowu w standardowej postaci: "
Spacje na początku i końcu wyrazu nieujętego w cudzysłowy mnie nie interesują.

Przykład:

Ala , ma kota, "mrówki, ", "psa, "papugę", ", ""rybki" ", "oraz brata"

i chcę z tego otrzymać (zapiszę każdy z tokenów w [ ], ale jedynie dla czytelności):

[Ala] [ma kota] [mrówki, ] [psa, "papugę", ] ["rybki" ] ["oraz brata"]

Wydawało mi się (na razie, bez uwzględnienia "), że takie coś podziała, ale niestety nie :(

String regexp = "[\"][^\"]*[\"]|[,]"; // ignoruje \" jako "
Scanner s = new Scanner(sourceString).useDelimiter("cokolwiek ?");
String token;
while (s.hasNext(regexp)) // czy to powoduje rekompilacie "patterna" w kazdym obrocie petli ?
    token = s.next(regexp);
/* .... */

Prosze o pomoc.

0

Delimiter to będzie znak końca wiersza
Nie pattern nie jest rekompilowany

Ja bym zrobił tak:

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String testString = "Ala  , ma kota, \"rybki\", \", oraz psa\"";
		String pattern = "[\"][^\"]*[,][\"]|[,]";
		for(String s: testString.split(pattern))
		System.out.println(s);
	}

}

wynik:

Ala  
 ma kota
 "rybki"
 "
 oraz psa"
0

Hmm... czemu tam jest załamanie wiersza ?

Chyba powinno być w wyniku:
Ala
ma kota
"rybki"
", oraz psa" - bo właśnie w tym jest problem, żeby nie "parsować" przecinków zawartych w cudzysłowach.

Ponadto czy jeśli podam (w wersji Javowej) string typu: "Ala, kot, \"pies\" i brat", to czy to mi wypluje poprawnie:
Ala, kot, "pies" i brat ?

0

Cos takiego mysle, ze bedzie wystarczajace.

[ ]*(?<!\\)".*?((?<!\\)")[ ]*|[^,]+

Zasada:
pierwsza sekcja, [ ](?<!\)".?((?<!\)")[ ] wyciaga wszystkie znaki (regex: .?), ujete w cudzyslow, ale pomija te cudzyslowy, ktore maja przed soba "", tj. backslash (regex: (?<!\)". Dodatkowo zbierane sa wszystkie puste znaki z obu koncow linii (regex: [ ]*).
Druga sekcja, [^,]+ wywolywana jest w przypadku porazki pierwszej oraz wyciaga wszystkie niepuste sekwencje, ktore nie zawieraja przecinka.
Wymagana bedzie jeszcze wtorna przerobka wyjscia, ale to juz nie powinno sprawic problemu.

0

Dzięki Wam obu, ale to nadal nie działa :( Albo ja jestem na tyle głupi, że ciągle czegoś nie dostrzegam :/

@ws: jeśli użyć tego jako delimiter (czyt.: String.split(pattern)) (raczej bez sensu, ale spróbowałem ;p) to wychodzą same przecinki (dla tekstu z przykładowego kodu podanego przez Koziołka), natomiast jeśli używać tego w next(pattern) w klasie Scanner (przy delimiterze \n) to nic nie wypluwa.

Wersja przerobiona przeze mnie (na Jave):

String pattern = "\\s*(?<!\\\\)\".*?((?<!\\\\)\")\\s*|[^,]+";

gdzie \s oznacza zbiór białych znaków.

0

Siema,
wybacz, powinienem poprzednio wrzucic kawalek kodu, dla wiekszej jasnosci.

import java.util.regex.*;

public class Regex {
	public static final void main(String[] args) {
	    String input = "Ala        ,       ma kota,      \"mrówki, \", \"psa, \\\"papugę\\\", \", \"\\\"rybki\\\" \", \\\"oraz brata\\\"";
	    String regex = "\\s*(?<!\\\\)\".*?((?<!\\\\)\")\\s*|[^,]+";
	    Pattern pattern = Pattern.compile(regex);
	    Matcher matcher = pattern.matcher(input);
	    System.out.println("pattern: " + pattern.pattern());
	    while(matcher.find()) {
	        System.out.print("[" + matcher.group().replaceAll("\\s+(\")|(\\s+$)|(^\\s+)", "").replaceAll("\\\\\"", "\"") + "]");
	    }
	    System.out.println();
	    //[Ala][ma kota][mrówki,][psa, "papugę",]["rybki"]["oraz brata"]
	}
}

Metoda String.split(String regex) uzywa wyrazenia regularnego jako separator, podobnie jak Scanner.useDelimiter(String pattern). Wiec w rezultacie obie metody zwroca dokladnie to, czego my nie chcemy.

0

Wow... wielkie dzięki :)

Ale myślałem, że Scanner.next(pattern) ignoruje ustawienie delimitera w scanerze i pozwala dzielić stringa wg tegoz patterna. Ale coz, widac sie mylilem.

Jeszcze raz dzieki :)

0

java.util.Scanner najpierw probuje podzielic stringi na tokeny, przy pomocy odpowiedniego separatora (domyslnie biale znaki, zmienianiany przy pomocy Scanner.useDelimiter(Pattern pattern)), a nastepnie metoda Scanner.next(Pattern pattern) zwraca tylko taki token, ktory odpowiada, przekazanemu jako parametr, wzorcowi. Ew. wyrzuca java.util.InputMismatchException jesli token nie pasuje do wzorca.
Pozdr.

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