栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Java正则表达式中捕获组的行为混乱

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java正则表达式中捕获组的行为混乱

当替换字符串中指定了一个不捕获任何内容的捕获组()时,参考实现中的Matcher类的文档未指定

appendReplacement
方法的行为
null
。尽管
group
方法的行为很明确,但方法中没有任何提及
appendReplacement

以下是上述情况在实施上的3种不同表现:

  • 对于上述情况,参考实现不添加任何内容(或者可以说添加空字符串)。
  • GNU Classpath和Android的实现
    null
    针对上述情况进行了补充。

为了简洁起见,一些代码已被省略,并以表示

...

1)Sun / Oracle JDK,OpenJDK(参考实现)

对于参考实现(Sun / Oracle JDK和OpenJDK),其代码

appendReplacement
似乎未从Java
6更改,并且当捕获组未捕获任何内容时,该代码不会追加任何内容:

        } else if (nextChar == '$') { // Skip past $ cursor++; // The first number is always a group int refNum = (int)replacement.charAt(cursor) - '0'; if ((refNum < 0)||(refNum > 9))     throw new IllegalArgumentException(         "Illegal group reference"); cursor++; // Capture the largest legal group string ... // Append group if (start(refNum) != -1 && end(refNum) != -1)     result.append(text, start(refNum), end(refNum));        } else {

参考

  • jdk6 / 98e143b44620
  • jdk8 / 687fd7c7986d

2)GNU类路径

GNU类路径是Java类库的完全重新实现,

appendReplacement
在上述情况下具有不同的实现。在Classpath中,Classpath
java.util.regex
包中的类只是对中类的包装
gnu.java.util.regex

Matcher.appendReplacement
RE.getReplacement
对匹配部分进行流程替换的调用:

  public Matcher appendReplacement (StringBuffer sb, String replacement)    throws IllegalStateException  {    assertMatchOp();    sb.append(input.subSequence(appendPosition,          match.getStartIndex()).toString());    sb.append(RE.getReplacement(replacement, match,        RE.REG_REPLACE_USE_BACKSLASHESCAPE));    appendPosition = match.getEndIndex();    return this;  }

RE.getReplacement
调用
REMatch.substituteInto
以获取捕获组的内容并直接附加其结果:

       case '$':         int i1 = i + 1;         while (i1 < replace.length () &&     Character.isDigit (replace.charAt (i1)))i1++;         sb.append (m.substituteInto (replace.substring (i, i1)));         i = i1 - 1;         break;

REMatch.substituteInto
REMatch.toString(int)
直接附加的结果,而不检查捕获组是否捕获了任何东西:

        if ((input.charAt (pos) == '$') && (Character.isDigit (input.charAt (pos + 1))))          { // Omitted pre parses the group number into val ... if (val < start.length)   {     output.append (toString (val));   }          }

并在捕获组未捕获时

REMatch.toString(int)
返回
null
(忽略了相关代码)。

  public String toString (int sub)  {    if ((sub >= start.length) || sub < 0)      throw new IndexOutOfBoundsException ("No group " + sub);    if (start[sub] == -1)      return null;    ...  }

因此,在GNU Classpath的情况下,

null
当替换字符串中指定了无法捕获任何内容的捕获组时,它将被附加到字符串中。

3)Android开源项目-Java核心库

在Android中,

Matcher.appendReplacement
调用private方法
appendevaluated
,该方法又将结果直接附加
group(int)
到替换字符串。

public Matcher appendReplacement(StringBuffer buffer, String replacement) {    buffer.append(input.substring(appendPos, start()));    appendevaluated(buffer, replacement);    appendPos = end();    return this;}private void appendevaluated(StringBuffer buffer, String s) {    boolean escape = false;    boolean dollar = false;    for (int i = 0; i < s.length(); i++) {        char c = s.charAt(i);        if (c == '\' && !escape) { escape = true;        } else if (c == '$' && !escape) { dollar = true;        } else if (c >= '0' && c <= '9' && dollar) { buffer.append(group(c - '0')); dollar = false;        } else { buffer.append(c); dollar = false; escape = false;        }    }    // This seemingly stupid piece of pre reproduces a JDK bug.    if (escape) {        throw new ArrayIndexOutOfBoundsException(s.length());    }}

由于

Matcher.group(int)
返回
null
用于捕获未能捕获组,
Matcher.appendReplacement
追加
null
当捕获组中的替换字符串被参考。

这两个抱怨您的人很可能在Android上运行他们的代码。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/515815.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号