Java 调用 replaceAll()方法报错:java.lang.IllegalArgumentException: character to be escaped is missing、Illegal group reference: group index is missing、named capturing group has 0 length name、named capturing group is missing trailing ‘}’、Illegal group reference等。
例如运行一下代码:
public static void main(String[] args) {String regex = "str";String replacement = "a$bc$d";String str = "test str replace.";String str1 = str.replaceAll(regex, replacement);System.out.println(str1);}
会抛出以下错误:
String的replaceAll(regex, replacement)方法会调用java.util.regex.Matcher.appendReplacement(sb, replacement)方法,appendReplacement(sb, replacement)方法的源码如下:
public Matcher appendReplacement(StringBuffer sb, String replacement) {// If no match, return errorif (first < 0)throw new IllegalStateException("No match available");// Process substitution string to replace group references with groupsint cursor = 0;StringBuilder result = new StringBuilder();while (cursor < replacement.length()) {char nextChar = replacement.charAt(cursor);if (nextChar == '\\') {cursor++;if (cursor == replacement.length())throw new IllegalArgumentException("character to be escaped is missing");nextChar = replacement.charAt(cursor);result.append(nextChar);cursor++;} else if (nextChar == '$') {// Skip past $cursor++;// Throw IAE if this "$" is the last character in replacementif (cursor == replacement.length())throw new IllegalArgumentException("Illegal group reference: group index is missing");nextChar = replacement.charAt(cursor);int refNum = -1;if (nextChar == '{') {cursor++;StringBuilder gsb = new StringBuilder();while (cursor < replacement.length()) {nextChar = replacement.charAt(cursor);if (ASCII.isLower(nextChar) ||ASCII.isUpper(nextChar) ||ASCII.isDigit(nextChar)) {gsb.append(nextChar);cursor++;} else {break;}}if (gsb.length() == 0)throw new IllegalArgumentException("named capturing group has 0 length name");if (nextChar != '}')throw new IllegalArgumentException("named capturing group is missing trailing '}'");String gname = gsb.toString();if (ASCII.isDigit(gname.charAt(0)))throw new IllegalArgumentException("capturing group name {" + gname +"} starts with digit character");if (!parentPattern.namedGroups().containsKey(gname))throw new IllegalArgumentException("No group with name {" + gname + "}");refNum = parentPattern.namedGroups().get(gname);cursor++;} else {// The first number is always a grouprefNum = (int)nextChar - '0';if ((refNum < 0)||(refNum > 9))throw new IllegalArgumentException("Illegal group reference");cursor++;// Capture the largest legal group stringboolean done = false;while (!done) {if (cursor >= replacement.length()) {break;}int nextDigit = replacement.charAt(cursor) - '0';if ((nextDigit < 0)||(nextDigit > 9)) { // not a numberbreak;}int newRefNum = (refNum * 10) + nextDigit;if (groupCount() < newRefNum) {done = true;} else {refNum = newRefNum;cursor++;}}}// Append groupif (start(refNum) != -1 && end(refNum) != -1)result.append(text, start(refNum), end(refNum));} else {result.append(nextChar);cursor++;}}// Append the intervening textsb.append(text, lastAppendPosition, first);// Append the match substitutionsb.append(result);lastAppendPosition = last;return this;}
可以看到这里面对“$”符号和"\\"符号进行了处理。出现以上错误的原因是:String的replaceAll(regex, replacement)方法的第一个参数支持正则表达式,如果参数replacement中出现符号“$”,会按照$1$2的分组模式进行匹配。当编译器发现“$”后跟的不是整数的时候,就会抛出“Illegal group reference”的异常。
处理办法:用JDK提供的方法,对特殊字符进行处理:
replacement = java.util.regex.Matcher.quoteReplacement(replacement);
该方法把符号"$“与符号”\\“添加了”\\"进行转义,前面的代码可以写成以下:
public static void main(String[] args) {String regex = "str";String replacement = "a$bc$d";replacement = java.util.regex.Matcher.quoteReplacement(replacement);String str = "test str replace.";String str1 = str.replaceAll(regex, replacement);System.out.println(str1);}