Methoden "a.b".replaceAll(".", "$")

Natac

Bekanntes Mitglied
Das Problem ist schnell umschrieben: Ich habe einen beliebigen String [c]a[/c] in dem ich gerne einen beliebigen Teil-String [c]b[/c] durch eine ebenfalls beliebigen String [c]c[/c] ersetzt wird. Mein einfacher Ansatz:
Java:
a.replaceAll(b, c);

Wenn nun in [c]b[/c] allerdings Steuerzeichen enthalten sind, sollen diese ignoriert werden, also:
Java:
a.replaceAll(Pattern.quote(b), c);

Nun habe ich folgenden Sonderfall gefunden, wo auch das nicht funktioniert:

Java:
public static void main(final String[] args) {
  String a = "a.b";
  String b = ".";
  String c = "$";
  System.out.println(a.replaceAll(Pattern.quote(b), c));
}

Wenn ich das so durchlaufen lasse, dann bekomme ich folgende Exception:

Java:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 1
	at java.lang.String.charAt(Unknown Source)
	at java.util.regex.Matcher.appendReplacement(Unknown Source)
	at java.util.regex.Matcher.replaceAll(Unknown Source)
	at java.lang.String.replaceAll(Unknown Source)
	at Test.main(Test.java:28)

Verwende ich [c]"\\$"[/c] statt $ funktioniert es (Was mir natürlich nichts bringt, da ich nicht weiß welche Steuerzeichen es noch gibt und vom Nutzer nicht verlangen kann, dass er diese kennt und ein "\" davor schreibt).

Das dumme an der Geschichte: Sowohl
Code:
a
wie auch
Code:
b
und
Code:
c
sollen vollkommen willkürliche Strings sein, die der Nutzer eingeben kann.

Daher meine Frage: Wie schreibe ich die Zeile
Code:
"a.b".replaceAll(".", "$");
so, dass ich "a$b" erhalte!? (String c quoten ist auch nicht, da ich dann eine [c]java.lang.IllegalArgumentException: Illegal group reference[/c] erhalte. ;( )

Irgendwer eine Idee? :bahnhof:
 
Zuletzt bearbeitet von einem Moderator:
Du bist Du auf ein interessantes Problem gestoßen. Ich habe mir den Quellcode von Matcher angeschaut. Das Problem tritt tatsächlich bei "$" im Replacementstrings auf. Abhilfe schafft "\\$". D.h., wen "$" im Replacementstring vorkommt, musst Du diesen Sonderfall abfangen. Alle anderen Replacementstrings müssten out of the Box funktionieren.

Ansonsten, wenn es tatsächlich nur um das Ersetzen von Literalen geht, ist bone2's Vorschlag sicher der beste.
 
das $ macht sich nicht so zum Spass zum Sonderzeichen,
sondern ist eine der wenigen, wenn nicht die einzige besondere Möglichkeit im Ersatz-String

'group reference' sagt ja schon die Fehlermeldung:
Java:
public class Test2
{
    public static void main(String[] args)
    {
        System.out.println("autoA aaaoA".replaceAll("(a..o)A", "$1B"));
    }
}
wird zu 'autoB aaaoB', man kann mehr selektieren als rausfliegt, Teile übernehmen, die Gruppen auch umsortieren, nur ergänzen ohne etwas zu löschen usw.
 
Java:
"a.b.c".replace(".","$")
kein regex, keine probleme
:toll: Das Leben kann so einfach sein. Aber wer nimmt schon nen "replace", wenn es ein "replaceAll" gibt ("replaceRegex" wäre passender gewesen, aber egal).

@SlaterB: Genau das wäre zu klären: Ist es nur "$", oder gibt es noch andere? Und wozu das $ im Ersatz-String da ist, ist auch klar, aber darum ging es ja gar nicht.
 
zumindest liefert
Java:
public class Test2 {
    public static void main(String[] args)  {
        for (int i = 0; i < 9999; i++)   {
            char c = (char)i;
            try    {
                "autoA aaaoA".replaceAll("(a..o)A", "" + c);
            }    catch (Exception e)     {
                System.out.println("Problem: " + c + ", " + i);
            }

        }
    }
}
nur
Code:
Problem: $, 36
Problem: \, 92

edit:
gibt der User zufällig \$ ein, also [c]\\$[/c], wäre es wiederum ungünstig, [c]\\\\$[/c] daraus zu machen 😉
aber wenn man beide Sonderzeichen ersetzt, kommt ja [c]\\\\\\$[/c] raus, das passt dann wieder
 
Zuletzt bearbeitet von einem Moderator:
Natac hat gesagt.:
@SlaterB: Genau das wäre zu klären: Ist es nur "$", oder gibt es noch andere?
Nein, es gibt nur das "$". Ein Blick in den Quellcode
Code:
java.util.regex.Matcher.replaceAll(Matcher.java:905)
zeigt das.
[EDIT]
Sorry, falsche Stelle aus dem Stacktrace rauskopiert. Der wichtige Teil des Quellcodes ist natürlich
Code:
java.util.regex.Matcher.appendReplacement(Matcher.java:771)
! Danke SlaterB
[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:
@nillehammer
welchen Code meinst du genau?

in appendReplacement steht u.a.
Java:
        while (cursor < replacement.length()) {
            char nextChar = replacement.charAt(cursor);
            if (nextChar == '\\') {
                cursor++;
                nextChar = replacement.charAt(cursor);
                result.append(nextChar);
                cursor++;
            } else if (nextChar == '$') {
...

hier noch eine günstige Methode, quoteReplacement, siehe auch dessen Javadoc:
Java:
    /**
     * Returns a literal replacement <code>String</code> for the specified
     * <code>String</code>.
     *
     * This method produces a <code>String</code> that will work
     * use as a literal replacement <code>s</code> in the
     * <code>appendReplacement</code> method of the {@link Matcher} class.
     * The <code>String</code> produced will match the sequence of characters
     * in <code>s</code> treated as a literal sequence. Slashes ('\') and
     * dollar signs ('$') will be given no special meaning.
     *
     * @param  s The string to be literalized
     * @return  A literal string replacement
     * @since 1.5
     */
    public static String quoteReplacement(String s) {
        if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1))
            return s;
        StringBuffer sb = new StringBuffer();
        for (int i=0; i<s.length(); i++) {
            char c = s.charAt(i);
            if (c == '\\') {
                sb.append('\\'); sb.append('\\');
            } else if (c == '$') {
                sb.append('\\'); sb.append('$');
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
 

Zurück
Oben