Java Regex Ersetzen durch Erfassungsgruppe

76

Gibt es eine Möglichkeit, einen regulären Ausdruck durch geänderten Inhalt der Erfassungsgruppe zu ersetzen?

Beispiel:

Pattern regex = Pattern.compile("(\\d{1,2})");
Matcher regexMatcher = regex.matcher(text);
resultString = regexMatcher.replaceAll("$1"); // *3 ??

Und ich möchte alle Vorkommen durch 1 $ multipliziert mit 3 ersetzen.

bearbeiten:

Sieht so aus, als ob etwas nicht stimmt :(

Wenn ich benutze

Pattern regex = Pattern.compile("(\\d{1,2})");
Matcher regexMatcher = regex.matcher("12 54 1 65");
try {
    String resultString = regexMatcher.replaceAll(regexMatcher.group(1));
} catch (Exception e) {
    e.printStackTrace();
}

Es wird eine IllegalStateException ausgelöst: Keine Übereinstimmung gefunden

Aber

Pattern regex = Pattern.compile("(\\d{1,2})");
Matcher regexMatcher = regex.matcher("12 54 1 65");
try {
    String resultString = regexMatcher.replaceAll("$1");
} catch (Exception e) {
    e.printStackTrace();
}

funktioniert gut, aber ich kann die $ 1 :( nicht ändern

bearbeiten:

Jetzt geht es :)

Nutzer
quelle
Wenn wir direkt an einer Saite arbeiten, haben wir endlich diese
Aquarius Power

Antworten:

80

Wie wäre es mit:

if (regexMatcher.find()) {
    resultString = regexMatcher.replaceAll(
            String.valueOf(3 * Integer.parseInt(regexMatcher.group(1))));
}

Verwenden Sie, um das erste Spiel zu erhalten #find(). Danach können Sie #group(1)sich auf diese erste Übereinstimmung beziehen und alle Übereinstimmungen durch den Wert der ersten Maches multipliziert mit 3 ersetzen.

Und falls Sie jede Übereinstimmung durch den Wert dieser Übereinstimmung multipliziert mit 3 ersetzen möchten:

    Pattern p = Pattern.compile("(\\d{1,2})");
    Matcher m = p.matcher("12 54 1 65");
    StringBuffer s = new StringBuffer();
    while (m.find())
        m.appendReplacement(s, String.valueOf(3 * Integer.parseInt(m.group(1))));
    System.out.println(s.toString());

Vielleicht möchten Sie die MatcherDokumentation durchsehen , in der dies und vieles mehr ausführlich behandelt werden.

Graf
quelle
9
Ja, aber Sie verlieren die ursprüngliche Zeichenfolge. Wenn es "a 1 2 3" ist, haben Sie nicht die a
Jasper Floor
20
Das war ziemlich hilfreich! Eine Ergänzung ist, dass Sie m.appendTail (s) aufrufen müssen, wenn Ihre Übereinstimmung mit einem Text und Ihre Übereinstimmungen nicht am Ende sind.
Mezzie
Seien Sie vorsichtig, wenn Sie Gruppen mit statischem Text wie Pattern.compile ("var myVar =" (. *) ";") Finden. - Es ersetzt alle gefundenen nicht nur die Gruppe. siehe auch den Link von John O.
Manuel Manhart
@ ManuelM.Sie können dieses Problem leicht auslassen, indem Sie anstelle von statischem Text positive Vorausschau- und Rückblick-Behauptungen verwenden. Auf diese Weise werden diese Teile nicht durch den Matcher ersetzt.
Klaar
Vielen Dank für die großartige Antwort. Sie haben den nützlichsten Teil dieses Beispiels für den Wertmultiplikator herausgeschnitten! Das hat es mir sehr deutlich gemacht! @mezzie Sehr gute Ergänzung! Obwohl es in den Java-Dokumenten für vorhanden ist java.util.regex.Matcher, ist es für die Leute, die ausschließlich auf diesen SO-Beitrag verweisen, sehr hilfreich. :)
Varun
11

Die Antwort von Earl gibt Ihnen die Lösung, aber ich dachte, ich würde hinzufügen, was das Problem ist, das Ihre verursacht IllegalStateException. Sie rufen an, group(1)ohne zuvor eine Übereinstimmungsoperation aufgerufen zu haben (z. B. find()). Dies ist nicht erforderlich, wenn Sie nur verwenden, $1da dies replaceAll()der Übereinstimmungsvorgang ist.

Draemon
quelle
5

Java 9 bietet eine Matcher.replaceAll(), die eine Ersatzfunktion akzeptiert:

resultString = regexMatcher.replaceAll(
        m -> String.valueOf(Integer.parseInt(m.group()) * 3));
shmosel
quelle
1

Quelle: Java-Implementierung von Rubys-Gsub

Verwendung:

// Rewrite an ancient unit of length in SI units.
String result = new Rewriter("([0-9]+(\\.[0-9]+)?)[- ]?(inch(es)?)") {
    public String replacement() {
        float inches = Float.parseFloat(group(1));
        return Float.toString(2.54f * inches) + " cm";
    }
}.rewrite("a 17 inch display");
System.out.println(result);

// The "Searching and Replacing with Non-Constant Values Using a
// Regular Expression" example from the Java Almanac.
result = new Rewriter("([a-zA-Z]+[0-9]+)") {
    public String replacement() {
        return group(1).toUpperCase();
    }
}.rewrite("ab12 cd efg34");
System.out.println(result);

Implementierung (neu gestaltet):

import static java.lang.String.format;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class Rewriter {
    private Pattern pattern;
    private Matcher matcher;

    public Rewriter(String regularExpression) {
        this.pattern = Pattern.compile(regularExpression);
    }

    public String group(int i) {
        return matcher.group(i);
    }

    public abstract String replacement() throws Exception;

    public String rewrite(CharSequence original) {
        return rewrite(original, new StringBuffer(original.length())).toString();
    }

    public StringBuffer rewrite(CharSequence original, StringBuffer destination) {
        try {
            this.matcher = pattern.matcher(original);
            while (matcher.find()) {
                matcher.appendReplacement(destination, "");
                destination.append(replacement());
            }
            matcher.appendTail(destination);
            return destination;
        } catch (Exception e) {
            throw new RuntimeException("Cannot rewrite " + toString(), e);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(pattern.pattern());
        for (int i = 0; i <= matcher.groupCount(); i++)
            sb.append(format("\n\t(%s) - %s", i, group(i)));
        return sb.toString();
    }
}
Mike
quelle