7

I can replace dollar signs by using Matcher.quoteReplacement. I can replace words by adding boundary characters:

from = "\\b" + from + "\\b"; 
outString = line.replaceAll(from, to);

But I can't seem to combine them to replace words with dollar signs.

Here's an example. I am trying to replace "$temp4" (NOT $temp40) with "register1".

        String line = "add, $temp4, $temp40, 42";
        String to = "register1";
        String from = "$temp4";
        String outString;


        from = Matcher.quoteReplacement(from);
        from = "\\b" + from + "\\b";  //do whole word replacement

        outString = line.replaceAll(from, to);
        System.out.println(outString);

Outputs

"add, $temp4, $temp40, 42"

How do I get it to replace $temp4 and only $temp4?

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
john k
  • 6,268
  • 4
  • 55
  • 59

4 Answers4

4

Use unambiguous word boundaries, (?<!\w) and (?!\w), instead of \b that are context dependent:

from = "(?<!\\w)" + Pattern.quote(from) + "(?!\\w)";

See the regex demo.

The (?<!\w) is a negative lookbehind that fails the match if there is a non-word char immediately to the left of the current location and (?!\w) is a negative lookahead that fails the match if there is a non-word char immediately to the right of the current location. The Pattern.quote(from) is necessary to escape any special chars in the from variable.

See the Java demo:

String line = "add, $temp4, $temp40, 42";
String to = "register1";
String from = "$temp4";
String outString;

from = "(?<!\\w)" + Pattern.quote(from) + "(?!\\w)";

outString = line.replaceAll(from, to);
System.out.println(outString);
// => add, register1, $temp40, 42
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • A note about [word boundaries](https://www.regular-expressions.info/wordboundaries.html): *There are three different positions that qualify as word boundaries: 1) Before the first character in the string, if the first character is a word character. 2) After the last character in the string, if the last character is a word character. 3) Between two characters in the string, where one is a word character*and the other is not a word character.* When you use variables you cannot rely on them. – Wiktor Stribiżew Apr 17 '18 at 23:41
  • And certainly you do not need `Matcher.quoteReplacement(from)` since that bit is not used in the replacement pattern, but in the regex pattern. You need to remove that line, just as I have it in the code snippet in my answer. – Wiktor Stribiżew Apr 17 '18 at 23:57
1

Matcher.quoteReplacement() is for the replacement string (to), not the regex (from). To include a string literal in the regex, use Pattern.quote():

from = Pattern.quote(from);
shmosel
  • 49,289
  • 6
  • 73
  • 138
  • @johnktejik Please read and understand the whole answer. Don't just copy the code and run. Also, if a method is unclear then take a look at the official documentation. On the other hand, the answer could contain all that information (and links to doc) with a full code example right from the start. Nonetheless, the answer is complete in a sense that it answers the question. – Zabuzard Apr 17 '18 at 23:37
  • @Zabuza This answer is helpful but does not answer the question. OP needs to match as whole word strings that can start/end with non-word chars. [My answer is the solution](https://stackoverflow.com/a/49888968/3832970). – Wiktor Stribiżew Apr 17 '18 at 23:38
1

$ has special meaning in regex (it means “end of input”). To remove any special meaning from characters in your target, wrap it in regex quote/unquote expressions \Q...\E. Also, because $ is not ”word” character, the word boundary won’t wiork, so use look arounds instead:

line = line.replaceAll("(?<!\\S)\\Q" + from + "\\E(?![^ ,])", to);
Bohemian
  • 412,405
  • 93
  • 575
  • 722
0

Normally, Pattern.quote is the way to go to escape characters that may be specially interpreted by the regex engine.

However, the regular expression is still incorrect, because there is no word boundary before the $ in line; space and $ are both non-word characters. You need to place the word boundary after the $ character. There is no need for Pattern.quote here, because you're escaping things yourself.

String from = "\\$\\btemp4\\b";

Or more simply, because you know there is a word boundary between $ and temp4 already:

String from = "\\$temp4\\b";

The from variable can be constructed from the expression to replace. If from has "$temp4", then you can escape the dollar sign and add a word boundary.

from = "\\" + from + "\\b";

Output:

add, register1, $temp40, 42
rgettman
  • 176,041
  • 30
  • 275
  • 357
  • But `from` is a variable, so position, and even existence, of chars that need escaping is almost certainly not known until runtime – Bohemian Apr 17 '18 at 23:31
  • @Bohemian The `from` variable can be constructed from the expression to be replaced, prepending `"\\$"` and appending `"\\b"`. – rgettman Apr 17 '18 at 23:33