[Java] Regex - wo ist der Haken?

gamp

Mitglied
Hallo alle zusammen!

Da Regex in allen Programmiersprachen fast gleich ist, hab ich das Thread mal in Coders Talk eröffnet, ich hoff das ist kein Problem, ansonsten bitte nach Java verschieben.

Ich benötige einen Regex der folgendes macht:

Here-11111-Is_Some_Weird_Stuff-Not-interesting_me-1111-ALLOWED
Here-11111-Is_-Some_Weird_Stuff-Not-interesting_me-1111-FORBIDDEN

Wenn der String auf -ALLOWED endet, soll er nicht matchen. Wenn der String jedoch auf -FORBIDDEN endet, soll er matchen und FORBIDDEN als Group 1 zurückgeben.

Mein Regex:
Code:
-(?!ALLOWED|ALLOWED2)((?>[^-]+))$
Gibt nur bei <STRING>-<IRGENDWAS> "IRGENDWAS" in Group 1 zurück, wenn <IRGENDWAS> nicht "ALLOWED" oder "ALLOWED2" ist. Habs auf http://www.regexplanet.com/simple/index.html und http://www.rubular.com/r/6UUh3yimSb getested, funktioniert bei beiden prima. Jedoch wenn ich es in Java so implementiere:
Code:
public class Test {
	
	static String str = "Here-11111-Is_-Some_Weird_Stuff-Not-interesting_me-1111-FORBIDDEN";
        //static String str = "Here-11111-Is_-Some_Weird_Stuff-Not-interesting_me-1111-ALLOWED"
	static String regex = "-(?!ALLOWED|ALLOWED2)((?>[^-]+))$";
	
	public static void main(String... args) throws IOException {
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(str);
		if(m.matches()) {
			System.out.println("group: "+m.group(1));
		} else {
			System.out.println("nope");
		}
	}
}
Matcht er irgendwie garnicht, weder "ALLOWED" noch "FORBIDDEN". Ich seh allerdings den Grund nicht, sind ja keine Chars drin die ich Escapen müsste? Hat jemand ne Idee worans liegt?

Mfg
 
Wenn er allowed nicht matchen soll und du dich somit nicht dafür interessierst? Warum zu Hölle packst du es dann mit in den Regex?

Also ganz generell ist der regex erstmal schlecht strukturiert und für den Verwendungszweck unpassend. Es könnte daran liegen, dass du mit ^ arbeitest was begin of line symbolisiert aber mit dem regex dann später nicht mehrzeilig matchst und das ganze dann nicht passt etc. Außerdem ist begin of line etwas anderes als eine Newline.

Der Grund warum es FORBIDDEN und auch nichts anderes in Group1 erscheint weil der regex wenn er matcht nur den - am Anfang konsumiert. Das ist eine Eigenschaft von negierten Gruppen, dass sie das folgende nicht einfassen, damit man was anderes damit machen kann. Und rein logisch kann die Engine damit ja auch nichts machen weil es eben nicht matcht.

Also müsstest du deinen Regex wohl so ändern:

Code:
-(FORBIDDEN)

Die Negation von Allowed ist eigentlch wirklich unnötig, da ja an genau der Stelle wo allowed nicht stehen soll forbidden steht. Eins geht nur. Wenn du nun natürlich mehr als den einen Fall hast und alles außer allowed matchen willst musst du forbidden negieren und dann entsprechend alles andere matchen durch eine andere Gruppe.

Achja: Und da du nun nichts wirklich unbestimmtes mehr suchst würde auch nen einfaches find ohne regex Engine genügen. Das dürfte etwas schneller gehn.
 
Also ganz generell ist der regex erstmal schlecht strukturiert und für den Verwendungszweck unpassend. Es könnte daran liegen, dass du mit ^ arbeitest was begin of line symbolisiert aber mit dem regex dann später nicht mehrzeilig matchst und das ganze dann nicht passt etc. Außerdem ist begin of line etwas anderes als eine Newline.
In einer Zeichenklasse steht das Zirkumflex für Negation, nicht für einen Zeilenanfang.

Achja: Und da du nun nichts wirklich unbestimmtes mehr suchst würde auch nen einfaches find ohne regex Engine genügen. Das dürfte etwas schneller gehn.
Dass das kein Fall für einen regulären Ausdruck ist, sehe ich auch so. Allerdings würde ich eher zur Verwendung von endsWith raten.

Grüße,
Matthias
 
Vorneweg: Meine Frage ist, wieso die REGEX-TESTER websites mir jeweils das richtige ausgeben, jedoch mein Java-Test-Programm nicht. Ich vermute es hat was mit Java String zu tun und ich Escape was nicht richtig?

Wenn er allowed nicht matchen soll und du dich somit nicht dafür interessierst? Warum zu Hölle packst du es dann mit in den Regex?.
Ganz einfach, da es 1000 Endungen -FORBIDDEN -ANYTHING gibt, die NICHT erlaubt sind, aber nur wenige (5 stueck) -BLA1 -BLA2 -BLA3 -BLA4 -BLA5 die erlaubt sind. Also wieso einen Regex gestalten bei dem ich 1000 Endungen hinzufügen muss damit ich immer "FORBIDDEN", "ANYTHING" etc. zurück bekomme? Also mach ich look-behind und schau ob er matched, wenn nicht -> OK, String erlaubt. Wenn er matcht -> FEHLER: BLA is forbidden.

Also ganz generell ist der regex erstmal schlecht strukturiert und für den Verwendungszweck unpassend. Es könnte daran liegen, dass du mit ^ arbeitest was begin of line symbolisiert aber mit dem regex dann später nicht mehrzeilig matchst und das ganze dann nicht passt etc. Außerdem ist begin of line etwas anderes als eine Newline.
Soweit ich weiss benutze ich ^ in einer Class am Anfang, also indiziert es eine Negation der in der Character Class enthaltenen Chars, und keinen Zeilenanfang. Lieg ich da falsch? Und ich will weder "Begin of Line" noch "Newline" matchen, dass es da einen Unterschied gibt ist mir aber durchaus klar.
Ich sehe auch nicht wieso der Regex schlecht strukturiert sein soll und für meinen Verwendungszweck unpassend ist. Kannst du mir bitte eine Beispiellösung mit besserer Performance und Strukturierung geben, die "passend" ist?

Der Grund warum es FORBIDDEN und auch nichts anderes in Group1 erscheint weil der regex wenn er matcht nur den - am Anfang konsumiert. Das ist eine Eigenschaft von negierten Gruppen, dass sie das folgende nicht einfassen, damit man was anderes damit machen kann. Und rein logisch kann die Engine damit ja auch nichts machen weil es eben nicht matcht.
Auf den oben angegebenen Regex-Test Websites erscheint sehr wohl "FORBIDDEN" in Group1 - exakt was ich wollte. Auch das Backtracking ist weitestgehend unterbunden, und - am Anfang wird "gestrippt". Du kannst es ja germ mal testen. Und da es matcht. macht es auch was.

Also müsstest du deinen Regex wohl so ändern:
Code:
-(FORBIDDEN)
Eben genau das will ich nicht haben.

Die Negation von Allowed ist eigentlch wirklich unnötig, da ja an genau der Stelle wo allowed nicht stehen soll forbidden steht. Eins geht nur. Wenn du nun natürlich mehr als den einen Fall hast und alles außer allowed matchen willst musst du forbidden negieren und dann entsprechend alles andere matchen durch eine andere Gruppe.
vll. hab ich mich falsch oder ungenau ausgedrückt, die Test-Klasse ist - wie eigentlich unschwer zu erkennen - ein Testprogramm. In meinem eigentlichen Programm werden pro Stunde ca. 2500 verschiedene Strings gegen den Regex gematcht, wenn er matcht gibt er "FORBIDDEN -> Reason: Group1 not allowed" aus.

Achja: Und da du nun nichts wirklich unbestimmtes mehr suchst würde auch nen einfaches find ohne regex Engine genügen. Das dürfte etwas schneller gehn
Wie oben: TEST-KLASSE, quasi ein Dummy der aber nicht wirklich in mein Eigentliches Programm reinkommt.


EDIT:

Es muss als Regex gemacht werden, da der Regex von einer Config File gelesen wird. Das endsWith() in diesem Fall besser wäre ist mir auch klar. Es hat schon seinen Sinn wieso ich das benutze.
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück