Java string.split(“\\S”)是如何工作的

Java string.split(“\\S”)是如何工作的,java,regex,ocpjp,Java,Regex,Ocpjp,我在做一个来自Ganesh和Sharma的《甲骨文认证专业人员》、《java》、《se》、《程序员考试》、《1z0-804》和《1z0-805》一书的问题 一个问题是: 考虑以下程序并预测输出: class Test { public static void main(String args[]) { String test = "I am preparing for OCPJP"; String[] tokens = test.split("\\S");

我在做一个来自Ganesh和Sharma的《甲骨文认证专业人员》、《java》、《se》、《程序员考试》、《1z0-804》和《1z0-805》一书的问题

一个问题是:

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

      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) 五,

    c) 十二,

    d) 十六,

  • 现在我明白了\S是一个正则表达式,表示将非空格字符作为分隔符。 但我对正则表达式是如何进行匹配的以及匹配结果是什么感到困惑 分割产生的实际代币

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

    for (String str: tokens){
      System.out.println("<" + str + ">");
    }
    
    for(字符串str:tokens){
    System.out.println(“”);
    }
    
    我得到了以下输出

    16
    < >
    < >
    < >
    < >
    
    所以有很多空字符串标记。 我就是不明白

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

    首先从
    \s
    (小写)开始,这是一个用于空白的正则表达式字符类,即空格“tabs”\t、“新行字符”\n“和“\r”、垂直制表符“\v”和一组其他字符

    \S
    (大写)与此相反,因此表示任何非空白字符

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

    至于为什么这些是空的

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

    同样的事情发生在
    我正在准备OCPJP
    字符串上,它已经被拆分,并且正则表达式匹配的点不在任何返回值中。由于该字符串中的大多数字母后面都跟有另一个字母,因此最终会出现一堆长度为零的字符串,只保留空白字符。

    复制自API:(粗体是我的)

    围绕给定正则表达式的匹配项拆分此字符串。 此方法的工作方式类似于通过调用具有 给定的表达式和零的极限参数尾随空 因此,结果数组中不包括字符串。

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

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

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

    结果是16而不是21的原因是:

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

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

    "/abc//def/ghi///".split("/")
    
    结果将有五个要素。第一个将是
    ,因为它不是尾随的空字符串;其他将是
    “abc”
    “def”
    ,和
    “ghi”
    。但是剩余的空字符串将从数组中删除

    在这种情况下:

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

    是一样的。由于非空格字符是分隔符,因此每个字母都是分隔符,但OCPJP字母基本上不计算在内,因为这些分隔符会导致随后丢弃的空字符串。因此,由于我正在为“”准备的“”中有15个字母,它们被视为分隔16个子字符串(第一个是
    ,最后一个是
    )。

    我试过你的例子,如果你用\\S替换\\S,会不会是打字错误?@mreiter这是为了认证考试,为什么他们会把这样一个棘手的案子扔进去呢?事实上,他们将正确答案(16)作为选择之一,这使得这不太可能是无意的。如果21是其中一个选择,我可能会弄错。嗨,不,这是\\S的反面。问题的关键是:为什么是16岁而不是21岁?为什么“OCPJP”不被视为一堆分离器?共有21个字母,但最后一个字母被忽略了……说得好,遗漏了问题的这一部分!感谢您指出这一点,并在回答中突出显示文档。感谢Pablo,如果您忽略最后一个空格后的空字符串,这是有意义的。这就解释了这个数字。16而不是21。这是一个稍有不同的观点,但假设您有一个逗号分隔的文件,文件末尾的值为空,如果没有填写,则表示它来自excel电子表格,用户没有输入值。这是否意味着String.split会将它们扔掉。如果您希望处理数据,可能会导致严重的错误。大声思考:-)。是的,这就是在分割CSV行时必须检查数组长度的原因。如果你把它和CSV格式没有任何标准的事实结合起来……在这种情况下,你可能想考虑<代码>分裂(“,”,-1)< /代码>。
    "I am preparing for OCPJP".split("\\S")