Замінити регулярний вираз 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.