Замінити регулярний вираз Java на групу захоплення


77

Чи є спосіб замінити регулярний вираз зміненим вмістом групи захоплення?

Приклад:

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

І я хотів би замінити всі випадки на $ 1, помножений на 3.

редагувати:

Схоже, щось не так :(

Якщо я використовую

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();
}

Він видає IllegalStateException: Збіг не знайдено

Але

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();
}

працює нормально, але я не можу змінити $ 1 :(

редагувати:

Тепер це працює :)


працюючи безпосередньо над струною, ми нарешті маємо це
Сила Водолія

Відповіді:


81

Як щодо:

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

Щоб отримати перший збіг, використовуйте #find(). Після цього ви можете використовувати #group(1)для посилання на цей перший збіг і замінити всі збіги на перше значення maches, помножене на 3.

І якщо ви хочете замінити кожен збіг значенням цього збігу, помноженим на 3:

    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());

Можливо, ви захочете переглянути Matcherдокументацію , де це та багато іншого детально висвітлено.


10
так, але ви втрачаєте початковий рядок. якщо це "a 1 2 3", у вас не буде a
Jasper Floor

20
Це було дуже корисно! Одне доповнення полягає в тому, що якщо ваше збіг тексту та збіги не закінчуються, вам потрібно буде викликати m.appendTail (s);
mezzie

Будьте обережні при пошуку груп із статичним текстом, наприклад Pattern.compile ("var myVar = \" (. *) \ ";"); - Він замінить всіх знайдених не тільки групу. див. також посилання Джона О.
Мануель Манхарт

@ ManuelM. Ви можете легко опустити цю проблему, використовуючи позитивні твердження про перспективу та оглядку замість статичного тексту. Таким чином ці частини не будуть замінені збігом.
klaar

Дякуємо за чудову відповідь, ви вирізали найкориснішу частину цього прикладу мультиплікатора! Це мені це дуже зрозуміло! @mezzie Дуже гарне доповнення! Незважаючи на те, що він присутній у документах Java для java.util.regex.Matcherлюдей, які посилаються виключно на цю публікацію SO, це буде дуже корисно. :)
варун

11

відповідь графа дає вам рішення, але я думав додати, в чому проблема, яка викликає вашу IllegalStateException. Ви телефонуєте group(1)без попереднього виклику операції відповідності (наприклад, find()). Це не потрібно, якщо ви просто використовуєте, $1оскільки replaceAll()це операція зіставлення.



1

Джерело: java-implementation-of-rubys-gsub

Використання:

// 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);

Реалізація (перероблена):

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();
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.