15

我在 Ganesh 和 Sharma 的书 oracle_certified_professional_java_se_7_programmer_exams_1z0-804_and_1z0-805 中做一个问题。

一个问题是:

  1. 考虑以下程序并预测输出:

      class Test {
    
        public static void main(String args[]) {
          String test = "I am preparing for OCPJP";
          String[] tokens = test.split("\\S");
          System.out.println(tokens.length);
        }
      }
    

    一)0

    b) 5

    c) 12

    d) 16

现在我明白 \S 是一个正则表达式意味着将非空格字符视为分隔符。但是我对正则表达式如何匹配以及拆分产生的实际标记感到困惑。

我添加了代码以打印出令牌,如下所示

for (String str: tokens){
  System.out.println("<" + str + ">");
}

我得到以下输出

16

<>

< >

<>

< >

<>

<>

<>

<>

<>

<>

<>

<>

< >

<>

<>

< >

所以很多空字符串标记。我只是不明白这一点。

我本来会认为,如果分隔符是上述文本中的非空格字符,那么所有字母字符都用作分隔符,所以如果我们匹配也会导致空字符串的标记,那么可能应该有 21 个标记。我只是不明白 Java 的正则表达式引擎是如何解决这个问题的。是否有任何正则表达式专家可以为我阐明此代码?

4

3 回答 3

12

从 API文档复制:(粗体是我的)

public String[] split(String regex)

围绕给定正则表达式的匹配拆分此字符串。此方法的工作方式就像通过使用给定表达式和零限制参数调用双参数拆分方法一样。因此,尾随的空字符串不包含在结果数组中。

例如,字符串“boo:and:foo”通过这些表达式产生以下结果:

 Regex  Result
   :    { "boo", "and", "foo" }
   o    { "b", "", ":and:f" }

检查第二个示例,其中最后 2 个“o”刚刚被删除:您的问题的答案是"OCPJP"子字符串被视为非空字符串不遵循的分隔符集合,因此该部分被修剪。

于 2014-10-09T14:43:41.010 回答
8

结果是 16 而不是 21 的原因是,来自javadocSplit

因此,尾随的空字符串不包含在结果数组中。

这意味着,例如,如果你说

"/abc//def/ghi///".split("/")

结果将有五个元素。第一个将是"",因为它不是尾随的空字符串;其他将是"abc", "","def""ghi"。但剩余的空字符串将从数组中删除。

在发布的案例中:

"I am preparing for OCPJP".split("\\S")

这是同一件事。由于非空格字符是定界符,每个字母都是定界符,OCPJP 字母本质上不算数,因为这些定界符会导致尾随空字符串被丢弃。因此,由于 中有 15 个字母"I am preparing for",因此它们被视为分隔 16 个子字符串(第一个是"",最后一个是" ")。

于 2014-10-09T14:46:55.640 回答
7

首先从\s(小写)开始,这是一个用于空白的正则表达式字符类,即空格''制表符'\t',换行符'\n'和'\r',垂直制表符'\v'和一堆其他角色。

\S(大写)与此相反,因此这意味着任何非空白字符。

因此,当您使用拆分此字符串“ I am preparing for OCPJP”时,\S您实际上是在每个字母处拆分字符串。您的令牌数组长度为 16 的原因。

现在至于为什么这些都是空的。

考虑下面的 String: Hello,World,如果我们使用 拆分它,,我们最终会得到一个长度为 2 的 String 数组,其中包含以下内容:HelloWorld。请注意,,它不在任何一个字符串中,它已被删除。

字符串也发生了同样的事情I am preparing for OCPJP,它已被拆分,并且您的正则表达式匹配的点不在任何返回值中。而且由于该字符串中的大多数字母后面都跟着另一个字母,因此您最终会加载长度为零的字符串,只保留空白字符。

于 2014-10-09T14:33:33.507 回答