Java Regex Replace with Capturing Group

JavaRegex

Java Problem Overview


Is there any way to replace a regexp with modified content of capture group?

Example:

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

And I'd like to replace all occurrence with $1 multiplied by 3.

edit:

Looks like, something's wrong :(

If I use

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

It throws an IllegalStateException: No match found

But

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

works fine, but I can't change the $1 :(

edit:

Now, it's working :)

Java Solutions


Solution 1 - Java

How about:

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

To get the first match, use #find(). After that, you can use #group(1) to refer to this first match, and replace all matches by the first maches value multiplied by 3.

And in case you want to replace each match with that match's value multiplied by 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());

You may want to look through Matcher's documentation, where this and a lot more stuff is covered in detail.

Solution 2 - Java

earl's answer gives you the solution, but I thought I'd add what the problem is that's causing your IllegalStateException. You're calling group(1) without having first called a matching operation (such as find()). This isn't needed if you're just using $1 since the replaceAll() is the matching operation.

Solution 3 - Java

Java 9 offers a Matcher.replaceAll() that accepts a replacement function:

resultString = regexMatcher.replaceAll(
        m -> String.valueOf(Integer.parseInt(m.group()) * 3));

Solution 4 - Java

Source: java-implementation-of-rubys-gsub

Usage:

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

Implementation (redesigned):

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionuserView Question on Stackoverflow
Solution 1 - JavaearlView Answer on Stackoverflow
Solution 2 - JavaDraemonView Answer on Stackoverflow
Solution 3 - JavashmoselView Answer on Stackoverflow
Solution 4 - JavaMikeView Answer on Stackoverflow