【问题标题】:How does string.split("\\S") work [duplicate]string.split("\\S") 如何工作[重复]
【发布时间】:2014-10-09 14:21:22
【问题描述】:

我在做 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);
        }
      }
    

    a) 0

    b) 5

    c) 12

    d) 16

现在我明白 \S 是一个正则表达式意味着将非空格字符视为分隔符。 但是我对正则表达式如何匹配以及什么是 split 产生的实际令牌。

我添加了如下代码来打印出令牌

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

我得到以下输出

16

<>

< >

<>

< >

<>

<>

<>

<>

<>

<>

<>

<>

< >

<>

<>

< >

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

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

【问题讨论】:

  • 我试过你的例子,如果你用 \\s 替换 \\S 会更有意义,这可能是一个错字吗?
  • @mreiterer 这是针对认证考试的,为什么他们抛出这样一个棘手的案例会显得很奇怪?他们将正确答案 (16) 作为选择之一,这一事实使得这不太可能是无意的。
  • P.S.如果 21 是其中一个选择,我可能会弄错。
  • 嗨,不,它是 \\S 的反义词。这很棘手。

标签: java regex ocpjp


【解决方案1】:

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

public String[] split(String regex)

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

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

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

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

【讨论】:

  • 感谢 Pablo,如果您忽略最后一个空格后的空字符串,这很有意义。那将解释这个数字。 16 而不是 21 ish。
  • 这是一个稍微不同的点,但是说你有一个逗号分隔的文件,最后的值是空的,说它们没有被填写,说它来自用户没有输入值的 excel 电子表格.这是否意味着 String.split 会将它们扔掉。如果您希望处理数据,可能会导致令人讨厌的错误。只是大声思考:-)。
  • 是的,这就是拆分 CSV 行时必须检查数组长度的原因。如果你把它和 CSV 格式缺乏任何标准的事实混在一起......
  • @FrankBrosnan 在这种情况下,您可能需要考虑split(",", -1)
【解决方案2】:

结果是16而不是21的原因是这个,来自javadoc for Split

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

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

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

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

在发布的情况下:

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

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

【讨论】:

    【解决方案3】:

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

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

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

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

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

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

    【讨论】:

    • 问题的重点是:为什么是 16 而不是 21?为什么“OCPJP”不被视为一堆分隔符?有 21 个字母,但最后一个被忽略...
    • 公平点,错过了问题的那一部分!感谢您指出这一点并在您的回答中突出显示文档。
    猜你喜欢
    • 1970-01-01
    • 2014-12-02
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    相关资源
    最近更新 更多