2

I have strings which look something like this: "You may use the promotion until [ Start Date + 30]". I need to replace the [ Start Date + 30] placeholder with an actual date - which is the start date of the sale plus 30 days (or any other number). [Start Date] may also appear on its own without an added number. Also any extra whitespaces inside the placeholder should be ignored and not fail the replacement.

What would be the best way to do that in Java? I'm thinking regular expressions for finding the placeholder but not sure how to do the parsing part. If it was just [Start Date] I'd use the String.replaceAll() method but I can't use it since I need to parse the expression and add the number of days.

Alex
  • 1,041
  • 3
  • 14
  • 32
  • 2
    Peek into MessageFormat.format javadocs, I guess it's the most suitable class for doing text replacements. – BigMike May 02 '12 at 11:01

1 Answers1

3

You should use a StringBuffer and Matcher.appendReplacement and Matcher.appendTail

Here's a complete example:

String msg = "Hello [Start Date + 30] world [ Start Date ].";
StringBuffer sb = new StringBuffer();

Matcher m = Pattern.compile("\\[(.*?)\\]").matcher(msg);

while (m.find()) {

    // What to replace
    String toReplace = m.group(1);

    // New value to insert
    int toInsert = 1000;

    // Parse toReplace (you probably want to do something better :)
    String[] parts = toReplace.split("\\+");
    if (parts.length > 1)
        toInsert += Integer.parseInt(parts[1].trim());

    // Append replaced match.
    m.appendReplacement(sb, "" + toInsert);
}
m.appendTail(sb);

System.out.println(sb);

Output:

Hello 1030 world 1000.
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • For some reason I had to use m.group(0) instead of m.group(1) to make it work, any idea why? Documentation says m.group(0) is the whole pattern and the actual groups start from 1 but it just didn't work in practice. With m.group(1) I got "IndexOutOfBoundsException: No group 1". Also, parts[1] contains the closing parenthesis so needed to filter out the non-digits as suggested here http://stackoverflow.com/questions/4030928/extract-digits-from-a-string-in-java – Alex May 03 '12 at 08:58
  • 1
    In an expression such as `\[(.*?)\]` a call to `find` on input `"ab [cd] ef"` would give `"[cd]"` in group 0 (the whole match) and `"cd"` in group 1 (the stuff inside the group `(...)` i.e. the part that matches `.*?`). – aioobe May 03 '12 at 09:07
  • Oops you're right I forgot to add the round parenthesis when building the regex, either way works for me. – Alex May 03 '12 at 09:13