当前位置:   article > 正文

Java 异常java.lang.IllegalArgumentException: Illegal group reference: group index is missing

illegal group reference: group index is missing

注:该文是本博主记录学习之用,没有太多详细的讲解,敬请谅解!

一、背景

想必大家在日常项目中对于字符串替换比较常用的方法都是用String类中的replace、replaceAll、replaceFirst等方法,本博主今天刚好遇到这些方法中一个小小的坑,因为平时不太注意,所以今天刚好踩雷了,所以撰写本文以做学习记录之用。

二、示例代码

在这里插入图片描述

以上示例代码输出结果
在这里插入图片描述
调用 replace、replaceAll、replaceFirst三个方法替换相同内容,由输出的结果可以看出,replace方法虽然成功但是没有替换到字符串,而replaceAll、replaceFirst这两个方法则抛出了异常:java.lang.IllegalArgumentException: Illegal group reference: group index is missing

既然报错了,我们就要找错,所以我们接下来分别看下这三个方法的源码处理:

  1. replace方法
    我们点进查看String类中replace的源码
    在这里插入图片描述
    从replace方法中我们会看到两个比较重要的点:
    第一个是Pattern.compile(target.toString(), Pattern.LITERAL),这里的正则匹配Pattern.LITERAL的意思就是:启用字面值解析模式, 指定此标志后,指定模式的输入字符串就会作为字面值字符序列来对待,输入序列中的元字符或转义序列不具有任何特殊意义(通俗的说就是输入值是什么就是什么)

    第二个是Matcher.quoteReplacement(replacement.toString()),这个是重点,我们跳到Matcher类查看quoteReplacement方法,这个方法主要是处理特殊符号$和\,为它俩加上转义符号
    在这里插入图片描述
    由此我们可以看得出为什么replace方法可以成功,但是却没有替换值,要想replace成功替换内容需要改成str.replace("?",replacement),不加任何转义符号。

  2. replaceAll和replaceFirst方法
    为什么这里要一起讲这两个方法,因为这两个方法抛出异常的处理逻辑是一样的,我们首先看下它们的源码,由String类中的replaceAll和replaceFirst方法中跳转到Matcher类中的replaceAll和replaceFirst方法,以下是Matcher类中的方法
    在这里插入图片描述
    在这里插入图片描述
    从上面两个方法中你可以看到它们都调用了一个appendReplacement方法,正是这个方法抛出了异常,接下来看appendReplacement方法的源码(图比较长,所以这里用代码显示)

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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

通过以上代码分析,可以看到这里面对 $ 符号和 \\ 符号进行了处理。出现异常错误的原因是:如果参数replacement中出现这两个符号,$符号处理会按照 $1的分组模式进行匹配。当编译器发现$后跟的不是整数的时候,就会抛出“Illegal group reference”的异常。 \\ 符号处理如果长度相等则也会抛出异常。

三、最终正常处理结果

既然知道了它抛出异常的原因,所以我们就更好的处理,我们前面也讲到了replace中调用到了Matcher类中quoteReplacement的方法进行转义,所以它能正常替换,因为replace是自动加上这个方法,所以不用做处理,调用replaceAll和replaceFirst方法时如果涉及到这两个特殊符号就要加上quoteReplacement进行转义。最终正常处理(如下图):

在这里插入图片描述在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/282310
推荐阅读
相关标签
  

闽ICP备14008679号