Заменить группу захвата
Если у меня есть регулярное выражение с группой захвата, например, foo(_+f)
. Если я сопоставляю это с строкой и хочу заменить первую группу захвата во всех совпадениях с помощью baz
, чтобы
foo___f blah foo________f
преобразуется в:
foobaz blah foobaz
Кажется, что нет простого способа сделать это, используя стандартные библиотеки. Если я использую Matcher.replaceAll(), это заменит все совпадения всего шаблона и преобразует строку в
baz blah baz
Очевидно, что я могу просто перебирать совпадения, хранить начальный и конечный индексы каждой группы захвата, а затем возвращаться и заменять их, но есть ли более простой способ?
Спасибо,
Дон
Ответы
Ответ 1
Я думаю, вы хотите что-то вроде этого?
System.out.println(
"foo__f blah foo___f boo___f".replaceAll("(?<=foo)_+f", "baz")
); // prints "foobaz blah foobaz boo___f"
Здесь вы просто заменяете все совпадение на "baz"
, но совпадение использует lookbehind, чтобы _+f
предшествовал foo
.
См. также
Если lookbehind невозможно (возможно, потому, что длина не является конечной), тогда просто запишите даже то, что вы НЕ заменяете, и ссылайтесь на них обратно в заменяющей строке.
System.out.println(
"fooooo_f boooo_f xxx_f".replaceAll("(fo+|bo+)(_+f)", "$1baz")
); // prints "fooooobaz boooobaz xxx_f"
Итак, мы фактически заменяем только то, что соответствует \2
.
Ответ 2
Поэтому я не думаю, что любой из этих ответов оправдывает более абстрактные случаи следующего вопроса, который я натолкнулся на себя, поэтому я написал код, который работает в более общем случае:
/**
*
* @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
Ответ 3
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
Ответ 4
Это где-нибудь близко....
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")