tags:

views:

679

answers:

3

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 :(

edit2:

Now, it's working :)

A: 

No, you can't do that with regex. Regex has no notion of numeric values, so doing arithmetic with numbers is not possible (assuming you wanted to convert "12 54 1 65" into "36 162 3 195").

Note that with some languages and regex implementations you can do this (Perl as Chris posted), but this is not a regex thing, and especially not a Java-regex thing. You said you have already resolved the issue, so I guess you went the "manual" way, converting each match into an integer and multiplying that with 3.

Bart Kiers
A: 

I think the answer for this question could help you.

Schtibe
+1  A: 

The definitive solution to this problem was posted by Elliott Hughes on his blog a couple years ago. Elliott keeps introducing pointless dependencies to other classes in the online version, so I'll post a stand-alone version here (the dependencies are only in the tests in the main() method).

import java.util.regex.*;

/**
 * A Rewriter does a global substitution in the strings passed to its
 * 'rewrite' method. It uses the pattern supplied to its constructor, and is
 * like 'String.replaceAll' except for the fact that its replacement strings
 * are generated by invoking a method you write, rather than from another
 * string. This class is supposed to be equivalent to Ruby's 'gsub' when
 * given a block. This is the nicest syntax I've managed to come up with in
 * Java so far. It's not too bad, and might actually be preferable if you
 * want to do the same rewriting to a number of strings in the same method
 * or class. See the example 'main' for a sample of how to use this class.
 *
 * @author Elliott Hughes
 */
public abstract class Rewriter
{
  private Pattern pattern;
  private Matcher matcher;

  /**
   * Constructs a rewriter using the given regular expression; the syntax is
   * the same as for 'Pattern.compile'.
   */
  public Rewriter(String regex)
  {
    this.pattern = Pattern.compile(regex);
  }

  /**
   * Returns the input subsequence captured by the given group during the
   * previous match operation.
   */
  public String group(int i)
  {
    return matcher.group(i);
  }

  /**
   * Overridden to compute a replacement for each match. Use the method
   * 'group' to access the captured groups.
   */
  public abstract String replacement();

  /**
   * Returns the result of rewriting 'original' by invoking the method
   * 'replacement' for each match of the regular expression supplied to the
   * constructor.
   */
  public String rewrite(CharSequence original)
  {
    this.matcher = pattern.matcher(original);
    StringBuffer result = new StringBuffer(original.length());
    while (matcher.find())
    {
      matcher.appendReplacement(result, "");
      result.append(replacement());
    }
    matcher.appendTail(result);
    return result.toString();
  }



  public static void main(String... args) throws Exception
  {
    String str = "12 54 1 65";

    // anonymous subclass
    Rewriter tripler = new Rewriter("(\\d{1,2})")
    {
      public String replacement()
      {
        int intValue = Integer.valueOf(group(1));
        return String.valueOf(intValue * 3);
      }
    };
    System.out.println(tripler.rewrite(str));

    // inline subclass
    System.out.println(new Rewriter("(\\d{1,2})")
    {
      public String replacement()
      {
        int intValue = Integer.valueOf(group(1));
        return String.valueOf(intValue * 3);
      }
    }.rewrite(str));

  }
}
Alan Moore