Strings ersetzen mit \

tomcom

Mitglied
Mein Code:
Java:
public class Test{
	public static void main(String[] args)   {
		String s = "Hello THIS";
		String backsl = "\\";
	
		System.out.println("This is a Backslash: "+backsl);
		System.out.println(s.replaceAll("THIS", "you"));
		System.out.println(s.replaceAll("THIS", "a"+backsl+"b"));
		System.out.println(s.replaceAll("THIS", backsl));
	}
}
Die Ausgabe:
Code:
This is a Backslash: \
Hello you
Hello ab
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 1
	at java.lang.String.charAt(String.java:658)
	at java.util.regex.Matcher.appendReplacement(Matcher.java:762)
	at java.util.regex.Matcher.replaceAll(Matcher.java:906)
	at java.lang.String.replaceAll(String.java:2162)
	at Test.main(Test.java:11)
Erwartet Ausgabe:
Code:
This is a Backslash: \
Hello you
Hello a\b
Hello \
Was läuft hier falsch? Generell hab ich beobachtet, dass bei String.replaceFirst() und String.replaceAll()
aus den zweiten Parameter entfernt werden.

Ich nutzen Openjdk 1.7 auf Suse Linux 13.1 64-bit.

Gruß,
Tom
 
Die Exception fliegt bei System.out.println(s.replaceAll("THIS", backsl));
Kann das mal jemand selbst kompilieren und schauen, ob die Exception auch fliegt.
Außerdem werden wie gesagt, keine Backslashe aus Parameter 2 ausgegeben (also aus dem Replace Teil).
 
Moin,

Die Exception fliegt bei System.out.println(s.replaceAll("THIS", backsl));
Kann das mal jemand selbst kompilieren und schauen, ob die Exception auch fliegt.
Ja, tut sie ;-)
Außerdem werden wie gesagt, keine Backslashe aus Parameter 2 ausgegeben (also aus dem Replace Teil)
Nein, das ist ja auch klar!
Mach Dir mal klar, was der doppelte Backslash bedeutet rsp. wozu er eingesetzt wird!!

Hier mal ein funktionierendes Beispiel, durch das es vielleicht für Dich klarer wird:
Java:
String sTMP = backsl + '\\';
String sTemp = "a" + sTMP + "b";
System.out.println( s.replaceAll("THIS", sTemp) );
System.out.println( s.replaceAll("THIS", sTMP) );
Sprich, du musst ggf. 4-fach escapen!

Gruß Klaus

EDIT
Hier noch ein paar Links zum Thema
http://www.java-forum.org/java-basics-anfaenger-themen/86407-backslash-escapen.html
Sonderzeichen in Strings und Konkatenation - Java als erste Programmiersprache - Javaschublade
Java Blog Buch : 03.04 Escape-Sequenzen
 
Zuletzt bearbeitet:
Das Problem liegt wohl irgendwo im Systemunabhänigen Bereich von Java.
Das sagt der Raspberry Pi B+ mit Oracle Java 8.0
Code:
root@raspberrypi:/tmp# java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) Client VM (build 25.0-b70, mixed mode)
root@raspberrypi:/tmp# java Test
This is a Backslash: \
Hello you
Hello ab
Exception in thread "main" java.lang.IllegalArgumentException: character to be escaped is missing
        at java.util.regex.Matcher.appendReplacement(Matcher.java:809)
        at java.util.regex.Matcher.replaceAll(Matcher.java:955)
        at java.lang.String.replaceAll(String.java:2210)
        at Test.main(Test.java:11)
 
Das Problem tritt auf, weil im 2. Parameter (das Replacement) 2 Zeichen eine besondere Bedeutung haben: "$" (spielt hier keine Rolle) und "\"

Dein Backslash wird also 2 x zum Escapen verwendet.
Zuerst bei der Angabe im Source. Dort sorgt er dafür, dass dein Sourcecode "\\" in Java intern zu "\" wird.
Bei replaceAll wird allerdings noch einmal versucht "\" als Start einer Escape-Sequenz zu interpretieren. Daher erwartet die Routine, dass dahinter noch ein Zeichen kommt.

Wie oben gesagt, müsste dein Replacement so aussehen "\\\\"
 
So, ich habe mal einen Workaround gebastelt.
In meinem Programm bekomme ich Texte, von denen ich nicht weiß, ob sie Backslashe enthalten.
Ich hab keinen Einfluß darauf und kann leider nicht "\\\\" statt "\\"schreiben.
Java:
public class StringFormat {
	public static String leadingZero(String s, int zeros){
		int i = 0;
		char[] chars = s.toCharArray();
		StringBuffer sb = new StringBuffer();
		while(chars.length > i && chars[i] >= '0' && chars[i] <= '9'){
			i++;
		}
		for(;zeros>i;zeros--){
			sb.append("0");
		}
		sb.append(s);
		
		return sb.toString();
	}
	
	public static String cutoffZeroBytes(String str){
		int i=-1;
		boolean hasZeroByte = false;
		//System.out.println("old length : "+str.length());
		for (char c : str.toCharArray()) {
			i++;
			if(c=='\0'){
				hasZeroByte = true;
				break;
			}
		}
		if(!hasZeroByte)
			return str;

		//System.out.println("new length : "+str.substring(0, i).length()+"\ti="+i);
		return str.substring(0, i);
	}
	
	public static String replaceAllwithBS(String orig, String regex, String repl){
		return orig.replaceAll(regex, repl.replaceAll("\\\\", "\\\\\\\\"));
	} 
	
	public static String replaceFirstwithBS(String orig, String regex, String repl){
		return orig.replaceFirst(regex, repl.replaceAll("\\\\", "\\\\\\\\"));
	} 
}
 
Wenn du in deinem Replacement bewußt die beiden Spezialzeichen nicht verwenden willst, dann reicht es deinen Replacementstring zu quoten.

In der Matcher Klasse findest du dazu : "public static String quoteReplacement(String s)"

Also:
Java:
        System.out.println(s.replaceAll("THIS", Matcher.quoteReplacement(backsl)));
 
Zuletzt bearbeitet:
Die Klasse Korrigiert Fehler aus der Stringklasse und Stellt Erweiterungen zur Verfügung.

Die Funktionen leadingZeros() stzt führende Nullen vor eine Zahl im Stringformat.
Beispiel ledingZero("1",2) ergibt 01.

Die Funktion cutoffZeroBytes() erstellt ein neues String-Objekt, aus dem alle Null-Byte-Felder entfernt wurden.
Werden Strings über das Netzwerk übertragen, passiert es leider, dass wenn der String nicht exakt die Länge des Buffers der Socket entspricht, dass im String-Objekt selbst, die Null-Bytes am Ende des buffers, Teil des Strings sind.
In Eclipse kann man das im Debug Modus schön sehen.
Man setzt einen Breakpoint unterhalb der Zeile, in der der Socket-Buffer (byte[]) in einen String gewandelt wurde.
Die Länge des Strings entspricht der Buffersize.
Schaut man sich im Debugfenster den Stringwert an, wird in diesem Moment, die Länge auf die korrekte Länge korrigiert.
Lässt man das Programm ohne den Wert anzuschauen weiterlaufen oder führt man es nicht im Debugmodus aus, bleibt die String-Lenth natürlich auf Buffersize und jedes String.equals() und String.equalsIgnoreCase() gibt immer false zurück.
 

Zurück
Oben