String.replaceAll Test, entweder ein Rätsel (und) oder ein Bug ****?

takidoso

Erfahrenes Mitglied
Hallo und Halli,
ich habe auf grund eines Phänomens ein Testprogramm gebaut, welches ein bischen replaceAll tut.
Ziel ist es die Namespace-angaben aus sowohl den Start als auch den EndeTags im XML-Teilstring zu entfernen.

Java:
public class ReplaceAllTest
{
	
	static private void multiReplaceAll(String inputString, String regex[], String replacement[])
	{
		for (int i=0; i<regex.length; i++)
		{
			System.out.println(inputString);
			inputString = inputString.replaceAll(regex[i], replacement[i]);
			
		}
		System.out.println(inputString);
		System.out.println("----");
	}
	
	static public void main (String[] args)
	{
		//String inputString = "<bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id>";
		String inputString = "<ar:CdtrSchmeId><bb3.1.2:Id><bb3.1.2:PrvtIdZ><bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id><bb3.1.2:SchmeNm><bb3.1.2:Prtry>SEPA</bb3.1.2:Prtry></bb3.1.2:SchmeNm></bb3.1.2:Othr></bb3.1.2:PrvtId></bb3.1.2:Id></ar:CdtrSchmeId>";
		String[] regex       = new String[] {"</.*?:","<.*?:"};
		String[] replacement = new String[] {"</","<"};;
		
		multiReplaceAll(inputString, regex, replacement);
		
		inputString = "<bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id><bb3.1.2:SchmeNm><bb3.1.2:Prtry>SEPA</bb3.1.2:Prtry></bb3.1.2:SchmeNm></bb3.1.2:Othr>";
		multiReplaceAll(inputString, regex, replacement);
		
		inputString = "<bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id>";
		multiReplaceAll(inputString, regex, replacement);
	}
}

hier die Ausgabe:
<ar:CdtrSchmeId><bb3.1.2:Id><bb3.1.2:prvtIdZ><bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id><bb3.1.2:SchmeNm><bb3.1.2:prtry>SEPA</bb3.1.2:prtry></bb3.1.2:SchmeNm></bb3.1.2:Othr></bb3.1.2:prvtId></bb3.1.2:Id></ar:CdtrSchmeId>
<ar:CdtrSchmeId><bb3.1.2:Id><bb3.1.2:prvtIdZ><bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</Id><bb3.1.2:SchmeNm><bb3.1.2:prtry>SEPA</Prtry></SchmeNm></Othr></PrvtId></Id></CdtrSchmeId>
<CdtrSchmeId><Id><PrvtIdZ><Othr><Id>DE09ZZZ00000000001<SchmeNm><Prtry>SEPA</Prtry></SchmeNm></Othr></PrvtId></Id></CdtrSchmeId>
----
<bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id><bb3.1.2:SchmeNm><bb3.1.2:prtry>SEPA</bb3.1.2:prtry></bb3.1.2:SchmeNm></bb3.1.2:Othr>
<bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</Id><bb3.1.2:SchmeNm><bb3.1.2:prtry>SEPA</Prtry></SchmeNm></Othr>
<Othr><Id>DE09ZZZ00000000001<SchmeNm><Prtry>SEPA</Prtry></SchmeNm></Othr>
----
<bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id>
<bb3.1.2:Id>DE09ZZZ00000000001</Id>
<Id>DE09ZZZ00000000001</Id>
----

nur die letzte Ausgabe ist wie erwartet.
bei den anderen beiden oben fehlt das Ende-Tag von <ID>

Sieht aus meiner Sicht zunächst aus wie ein Bug!

Wie kann man sich das erklären?
Gäbe es dazu einen Workaround? Wer kennt eine bessere Regex-Formulierung, die mir das gewünschte ergebnis gibt?

mit amkopfkratzenden Grüßen

Takidoso
 
Zuletzt bearbeitet:
Hi,

also ich kann mir das auch nicht so wirklich erklären. Aber bei deine Regex würde ich ein wenig ändern:
Java:
String[] regex       = new String[] {"</.*:","<.*:"};
Wenn die Fragezeichen (Zeichen kommt ein- oder keinmal vor) weg sind, dann kann es nur matchen, solange der String den Teil enthält den du entfernen willst. Denke ich zumindest. Habe es selber nicht ausprobiert.

// ---
// EDIT
Jetzt fällt mir auch gerade noch auf, dass beide Regexe gleich matchen. ;)
Ob du das nun so schreibst '</.*:' oder so '<.*:' ist vollkommen egal, da '.*' auf alle Zeichen (einschließlich '/') matchen sollte.

Gruß

Fabio
 
Zuletzt bearbeitet:
Hier mal meine Vorschlag für einen Ausdruck:

Java:
System.out.println( inputString.replaceAll("<(\\/?)(?>.+?):(.+?)>", "<$1$3>") );
 
Zuletzt bearbeitet:
Nun weiß ich warum es nicht funktioniert.
Nebenbei das *? in meinen Ausdrücken ist als Quantifier gedacht der da aussagt "reluctant" zu sein

Hier eine tabelle diesbezüglich:
Code:
Greedy   Reluctant  Possessive Meaning 
--------------------------------------------------------------------
X?        X****       X?+      X, once or not at all 
X*        X*?         X*+      X, zero or more times 
X+        X+?         X++      X, one or more times 
X{n}     X{n}?       X{n}+     X, exactly n times 
X{n,}    X{n,}?      X{n,}+    X, at least n times 
X{n,m}   X{n,m}?   X{n,m}+     X, at least n but not more than m times

Nun zur Erläuterung was er bei den Fehlsituationen tatsächlich (richtig) gemacht hatte (also kein Bug)

<bb3.1.2:Id>DE09ZZZ00000000001</Id><bb3.1.2:SchmeNm>...
er sieht und änder tdie erste Stelle wo er den Ausdruck findet
und hier ist die 2. Stelle die er findet:
<bb3.1.2:Id>DE09ZZZ00000000001</Id><bb3.1.2:SchmeNm>

um das zu beheben ist die 2. ReGex zu korrigieren, in dem man sagt das man einen String sucht der keine spitze-Klammer-auf enthält
also anstelle von:
Code:
"<.*?:"
dieses hier
Code:
"<[^<]*?:"

und dann klappt es auch (mit dem Nachbarn :))

in diesem Sinne

Takidoso
 
Hier mal meine Vorschlag für einen Ausdruck:

Java:
System.out.println( inputString.replaceAll("<(\\/?)(?>.+?):(.+?)>", "<$1$3>") );
das habe ich nun auch mal ausprobiert:

Java:
inputString = "<ar:CdtrSchmeId><bb3.1.2:Id><bb3.1.2:PrvtIdZ><bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id><bb3.1.2:SchmeNm><bb3.1.2:Prtry>SEPA</bb3.1.2:Prtry></bb3.1.2:SchmeNm></bb3.1.2:Othr></bb3.1.2:PrvtId></bb3.1.2:Id></ar:CdtrSchmeId>";
System.out.println( inputString.replaceAll("<(\\/?)(?>.+?):(.+?)>", "<$1$3>") );

hier der output:
Code:
<ar:CdtrSchmeId><bb3.1.2:Id><bb3.1.2:PrvtIdZ><bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id><bb3.1.2:SchmeNm><bb3.1.2:Prtry>SEPA</bb3.1.2:Prtry></bb3.1.2:SchmeNm></bb3.1.2:Othr></bb3.1.2:PrvtId></bb3.1.2:Id></ar:CdtrSchmeId>

drollig es scheint hier alls unverändert :)
aber danke trotzdem
 
Ich hatte den Beitrag editiert, um aus der mittleren Gruppe eine atomare Gruppe zu machen, weil wir für die zweite Gruppe keine Rückwärtzreferenz benötigen. Hätte es aber vorher testen sollen (bzw. habe es nicht kompiliert, sondern nur ausgeführt)

Java:
System.out.println( inputString.replaceAll("<(\\/?)(.+?):(.+?)>", "<$1$3>") );
 
wo hast du es denn ausgeführt, wenn Du es nicht kompliiert hast****?
Aber Du hattest mich durchaus auf eine andere ähnliche Idee gebracht um nicht zweimal einen Replace machen zu müssen:
Java:
inputString = "<ar:CdtrSchmeId><bb3.1.2:Id><bb3.1.2:PrvtIdZ><bb3.1.2:Othr><bb3.1.2:Id>DE09ZZZ00000000001</bb3.1.2:Id><bb3.1.2:SchmeNm><bb3.1.2:Prtry>SEPA</bb3.1.2:Prtry></bb3.1.2:SchmeNm></bb3.1.2:Othr></bb3.1.2:PrvtId></bb3.1.2:Id></ar:CdtrSchmeId>";
System.out.println( inputString.replaceAll("(<|</)[^/]+?:(.+?>)", "$1$2") );
Ich wußte gar nicht dass bei dem Replace auch die Gruppen die man findet ersetzt werden können insofern wieder was neues gelernt :-D
 
Du kannst sogar in dem Suchstring die Gruppen direkt nochmal verwenden. Das ist zum Beispiel praktisch, wenn du öffnende und die dazu gehörigen schließenden Tags suchst.

Ich habe in der Konsole nur Pfeil hoch + Enter gedrückt ("java Program") anstatt zweimal hoch ("javac Program.java"). Wenn man sonst nur mit Skript sprachen zu tun hat, vergisst man das kompilieren manchmal und für so was starte ich keine IDE.
 
Zurück