заменить группу захвата - PullRequest
11 голосов
/ 27 мая 2010

Если у меня есть регулярное выражение с группой захвата, например, foo(_+f). Если я сопоставлю это со строкой и захочу заменить первую группу захвата во всех совпадениях на baz, чтобы

foo___f blah foo________f

преобразуется в:

foobaz blah foobaz

Кажется, нет простого способа сделать это, используя стандартные библиотеки. Если я использую Matcher.replaceAll () , это заменит все совпадения всего шаблона и преобразует строку в

baz blah baz

Очевидно, что я могу просто перебрать совпадения, сохранить начальный и конечный индексы каждой группы захвата, затем вернуться и заменить их, но есть ли более простой способ?

Спасибо, Дон

Ответы [ 4 ]

25 голосов
/ 27 мая 2010

Я думаю, вы хотите что-то подобное?

    System.out.println(
        "foo__f blah foo___f boo___f".replaceAll("(?<=foo)_+f", "baz")
    ); // prints "foobaz blah foobaz boo___f"

Здесь вы просто заменяете все совпадение на "baz", но совпадение использует lookbehind, чтобы гарантировать, что _+f предшествует foo.

Смотри также


Если смотреть назад невозможно (возможно, из-за того, что длина не конечна), просто захватите даже то, что вы НЕ заменяете, и отошлите их обратно в строке замены.

    System.out.println(
        "fooooo_f boooo_f xxx_f".replaceAll("(fo+|bo+)(_+f)", "$1baz")
    ); // prints "fooooobaz boooobaz xxx_f"

Таким образом, здесь мы фактически заменяем только то, что соответствует \2.

4 голосов
/ 01 августа 2012

Так что я не думаю, что какой-либо из этих ответов оправдывает более абстрактные случаи следующего вопроса, с которым я столкнулся, поэтому я написал некоторый код, который работает в более общем случае:

/**
 * 
 * @param regex  Pattern to find in oldLine. Will replace contents in ( ... ) - group(1) - with newValue
 * @param oldLine  Previous String that needs replacing
 * @param newValue  Value that will replace the captured group(1) in regex
 * @return
 */
public static String replace(String regex, String oldLine, String newValue)
{
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(oldLine);
    if (m.find())
    {
        return m.replaceAll(replaceGroup(regex, newValue));
    }
    else
    {
        throw new RuntimeException("No match");
    }
}

/**
 * Replaces group(1) ( ... ) with replacement, and returns the resulting regex with replacement String
 * @param regex  Regular expression whose parenthetical group will be literally replaced by replacement
 * @param replacement  Replacement String
 * @return
 */
public static String replaceGroup(String regex, String replacement)
{
    return regex.replaceAll("\\(.*\\)", replacement);
}

На вашем примере это именно так, как вы описываете:

String regex = "foo(_+f)";
String line = "foo___f blah foo________f";
System.out.println(FileParsing.replace(regex, line, "baz"));

Распечатывается:

foobaz blah foobaz
1 голос
/ 27 мая 2010
p = Pattern.compile("foo(g.*?f)");
m = p.matcher("foog___f blah foog________f");
s = m.replaceAll("foobaz");//replace with foobaz instead of just baz
System.out.println(s);//foobaz blah foobaz
0 голосов
/ 27 мая 2010

Это где-нибудь близко ....

String[] s = {"foo___f blah foo________f", 
    "foo___f blah goo________f"};
for(String ss: s)
System.out.println(ss.replaceAll("(foo)(_+)f", "$1baz"));

То есть, добавить группу захвата для 'foo'. В противном случае простая замена будет

"foo___f blah foo________f".replaceAll("(_+)f", "baz")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...