出现场景
Java在调用String的replaceAll()方法时,报错Caused by: java.lang.IndexOutOfBoundsException: No group 8(数字可能也是1,2,3,4,5.。。。等等);
出现该异常原因:索引越界,使用非法索引访问数组。 索引为负数或大于或等于数组的大小。取值的时候超出了数组的长度,比如数组长度是1,当你取第二个的时候就会报这个异常。
或者出现以下某一个报错的时候:
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等。
尝试运行以下Java代码 :
情况1,出现报错java.lang.IndexOutOfBoundsException: No group
@Test
public void replaceTest(){
String regex = "s";
String replacement = "$122";
String str = "test str replace.";
String str1 = str.replaceAll(regex, replacement);
System.out.println(str1);
}
会出现以下报错:
情况2:出现报错:java.lang.IllegalArgumentException: Illegal group reference
@Test
public void replaceTest(){
String regex = "s";
String replacement = "$f";
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)方法
我们来看一下这个方法是的源码就知道问题所在了
public Matcher appendReplacement(StringBuffer sb, String replacement) {
// If no match, return error
if (first < 0)
throw new IllegalStateException("No match available");
// Process substitution string to replace group references with groups
int 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 replacement
if (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 group
refNum = (int)nextChar - '0';
if ((refNum < 0)||(refNum > 9))
throw new IllegalArgumentException(
"Illegal group reference");
cursor++;
// Capture the largest legal group string
boolean done = false;
while (!done) {
if (cursor >= replacement.length()) {
break;
}
int nextDigit = replacement.charAt(cursor) - '0';
if ((nextDigit < 0)||(nextDigit > 9)) { // not a number
break;
}
int newRefNum = (refNum * 10) + nextDigit;
if (groupCount() < newRefNum) {
done = true;
} else {
refNum = newRefNum;
cursor++;
}
}
}
// Append group
if (start(refNum) != -1 && end(refNum) != -1)
result.append(text, start(refNum), end(refNum));
} else {
result.append(nextChar);
cursor++;
}
}
// Append the intervening text
sb.append(text, lastAppendPosition, first);
// Append the match substitution
sb.append(result);
lastAppendPosition = last;
return this;
}
可以从源码看出,appendReplacement()方法对反斜杠\和美元符号$
进行了特殊处理。上述示例的代码可以看出,需要替换的字符串中含有了$,所以appendReplacement()对其进行了特殊处理。
出现以上错误的原因是:String的replaceAll(regex, replacement)方法的第一个参数支持正则表达式,如果参数replacement中出现符号“$”,会按照$1$2的分组模式进行匹配。当编译器发现“$”后跟的不是整数的时候,就会抛出“Illegal group reference”的异常。当编译器发现$后面跟的是数字,却找不到分组时,就会抛出“No group ”的异常。
解决方法
需要将字符串中的反斜杠\\和美元符号$进行转义。可以使用JDK提供的方法,对特殊字符进行处理:
// 将replacement中的特殊字符进行转义
replacement = java.util.regex.Matcher.quoteReplacement(replacement);
前面的代码可以改成:
@Test
public void replaceTest(){
String regex = "s";
String replacement = "$f";
String str = "test str replace.";
replacement = java.util.regex.Matcher.quoteReplacement(replacement);
String str1 = str.replaceAll(regex, replacement);
System.out.println(str1);
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/261535.html