Home > other >  replaceFirst , Why can't special symbols be replaced?
replaceFirst , Why can't special symbols be replaced?

Time:11-22

replaceFirst , Why can't special symbols be replaced?

System.out.println(cal); // 1 * 1 1 <==== ???

package com;

import org.apache.commons.lang.StringUtils;

public class Test {

    public static void main(String[] args) {

        String cal = "[aaa] * [aaa]   [bbb]";

        int cnt = StringUtils.countMatches(cal, "[");

        String delStr = "";

        for (int i = 0; i < cnt; i  ) {
            delStr = cal.substring(cal.indexOf("["), cal.indexOf("]")   1);
            cal = cal.replaceFirst("[" delStr  "]", "1");
        }

        System.out.println(cal); // 1 * 1   1 <==== ???
    }
}

CodePudding user response:

Special symbols which are used in the regular expressions need to be either escaped using \ or entire expression should be treated as a string literal with the help of Pattern.quote which basically surrounds the regex with the pair of \Q and \E.

Also, in the presented code delStr would include the pair of the square brackets, thus the replacement should occur for the regexp [[aaa]], and unexpected match -- first a in the first occurrence of [aaa] -- is found and replaced for such pattern instead of implied replacement. Then for the following iterations the cal looks like [1aa] * [aaa] [bbb] and cal.indexOf("[") bring the same first occurrence several times.

So, the following escape of the special symbols described above works fine:

String delStr = "";

for (int i = 0; i < cnt; i  ) {
    delStr = cal.substring(cal.indexOf("["), cal.indexOf("]")   1);

    cal = cal.replaceFirst("\\Q"   delStr   "\\E", "1"); // literal mode
    // or cal = cal.replaceFirst(Pattern.quote(delStr), "1");
}

Also, this solution may be refactored to completely get rid of the loop and String::indexOf / String::replaceFirst methods, because the implied result means that all the substrings between [ and ] including the brackets should be replaced with 1, that is, String::replaceAll would do the entire job:

cal = cal.replaceAll("\\[[^]]*\\]", "1"); // 1 * 1   1
  • Related