Можно ли заменить группы в Java regex?

У меня есть этот код, и я хочу знать, если я могу заменить только группы (не все шаблоны) в Java regex. Код:

 //...
 Pattern p = Pattern.compile("(\\d).*(\\d)");
    String input = "6 example input 4";
    Matcher m = p.matcher(input);
    if (m.find()) {

        //Now I want replace group one ( (\\d) ) with number 
       //and group two (too (\\d) ) with 1, but I don't know how.

    }

Ответ 1

Используйте $n (где n - цифра), чтобы ссылаться на захваченные подпоследовательности в replaceFirst(...). Я предполагаю, что вы хотели заменить первую группу литеральной строкой "число", а вторую группу - значением первой группы.

Pattern p = Pattern.compile("(\\d)(.*)(\\d)");
String input = "6 example input 4";
Matcher m = p.matcher(input);
if (m.find()) {
    // replace first number with "number" and second number with the first
    String output = m.replaceFirst("number $2$1");  // number 46
}

Рассмотрим (\D+) для второй группы вместо (.*). * является жадным совпадением и сначала потребляет последнюю цифру. Затем совпадению придется отступить, когда он поймет, что окончательный (\d) не имеет ничего общего, прежде чем он сможет соответствовать последней цифре.

Ответ 2

Вы можете использовать Matcher#start(group) и Matcher#end(group) для создания общего метода замены:

public static String replaceGroup(String regex, String source, int groupToReplace, String replacement) {
    return replaceGroup(regex, source, groupToReplace, 1, replacement);
}

public static String replaceGroup(String regex, String source, int groupToReplace, int groupOccurrence, String replacement) {
    Matcher m = Pattern.compile(regex).matcher(source);
    for (int i = 0; i < groupOccurrence; i++)
        if (!m.find()) return source; // pattern not met, may also throw an exception here
    return new StringBuilder(source).replace(m.start(groupToReplace), m.end(groupToReplace), replacement).toString();
}

public static void main(String[] args) {
    // replace with "%" what was matched by group 1 
    // input: aaa123ccc
    // output: %123ccc
    System.out.println(replaceGroup("([a-z]+)([0-9]+)([a-z]+)", "aaa123ccc", 1, "%"));

    // replace with "!!!" what was matched the 4th time by the group 2
    // input: a1b2c3d4e5
    // output: a1b2c3d!!!e5
    System.out.println(replaceGroup("([a-z])(\\d)", "a1b2c3d4e5", 2, 4, "!!!"));
}

Проверьте онлайн-демо.

Ответ 3

Добавьте третью группу, добавив parens вокруг .*, затем замените подпоследовательность на "number" + m.group(2) + "1". например:.

String output = m.replaceFirst("number" + m.group(2) + "1");

Ответ 4

Для получения позиций группы вы можете использовать методы matcher.start() и matcher.end(). Поэтому, используя эти позиции, вы можете легко заменить любой текст.