用正则表达式\ w \ w *拆分字符串? \ w +?

时间:2012-03-18 18:16:28

标签: java regex

我正在学习regexp并且认为我开始抓紧了。但是......

我试图拆分一个字符串,我需要帮助才能理解这样一个简单的事情:

String input = "abcde";
System.out.println("[a-z] " + Arrays.toString(input.split("[a-z]")));
System.out.println("\\w " + Arrays.toString(input.split("\\w")));
System.out.println("\\w*? " + Arrays.toString(input.split("\\w*?")));
System.out.println("\\w+? " + Arrays.toString(input.split("\\w+?")));

The output is
[a-z] - []
\w    - []
\w*?  - [, a, b, c, d, e]
\w+?  - []

为什么两个第一行中没有任何一行在任何字符上拆分字符串? 第三个表达式\ w *?,(问号防止贪婪)按照我的预期工作,在每个字符上分割字符串。星号,零个或多个匹配,返回一个空数组。

我在NotePad ++和程序中尝试了这个表达式,它显示了5个匹配项,如:

Scanner ls = new Scanner(input);
while(ls.hasNext())
    System.out.format("%s ", ls.findInLine("\\w");

Output is: a b c d e

这真让我困惑

3 个答案:

答案 0 :(得分:10)

如果使用正则表达式拆分字符串,则基本上可以告诉应该剪切字符串的位置。这必然会削减你与正则表达式相匹配的东西。这意味着如果您在\w处拆分,则每个字符都是一个拆分点,并返回它们之间的子串(全部为空)。 Java会自动删除尾随的空字符串,如the documentation

中所述

这也解释了为什么延迟匹配\w*?将为您提供每个字符,因为它将匹配任何字符(零宽度)之间(和之前和之后)的每个位置。剩下的就是字符串本身的字符。

让我们分解一下:

  1. [a-z] \w \w+?

    你的字符串是

    abcde
    

    比赛如下:

     a  b  c  d  e
    └─┘└─┘└─┘└─┘└─┘
    

    会在匹配项之间留下的子字符串,所有这些都是空的。

    上述三个正则表达式在这方面表现相同,因为它们只匹配单个字符。 \w+?会这样做,因为它没有任何其他约束可能会使+?尝试匹配的不仅仅是最低限度(毕竟它是懒惰的)。

  2. <强> \w*?

      a  b  c  d  e
    └┘ └┘ └┘ └┘ └┘ └┘
    

    在这种情况下,匹配是字符之间,留下以下子字符串:

    "", "a", "b", "c", "d", "e", ""
    
    然而,

    Java抛出了空尾的那个。

答案 1 :(得分:3)

让我们将每次调用分解为String#split(String)。从Java文档中注意到“方法就像通过使用给定表达式调用the two-argument split method并且限制参数为零一样工作是关键。因此,结果数组中不包括尾随空字符串。”

"abcde".split("[a-z]"); // => []

这个匹配每个字符(a,b,c,d,e)并且只产生它们之间的空字符串,这些字符串被省略。

"abcde".split("\\w")); // => []

同样,字符串中的每个字符都是一个单词字符(\w),因此结果是空字符串,省略。

"abcde".split("\\w*?")); // => ["", "a", "b", "c", "d", "e"]

在这种情况下,*表示“前面项目的零个或多个”(\w),它与空表达式匹配七次(一次在字符串的开头,然后在每个字符之间一次) )。所以我们得到第一个空字符串,然后是每个字符。

"abcde".split("\\w+?")); // => []

这里+表示“前面一项或多项”(\w)与整个输入字符串匹配,只产生空字符串,省略。

再次使用input.split(regex, -1)尝试这些示例,您应该会看到所有空字符串。

答案 2 :(得分:1)

String.split会在模式的每个匹配项处剪切字符串:

  

此方法返回的数组包含此字符串的每个子字符串,该子字符串由与给定表达式匹配的另一个子字符串终止,或者以字符串的结尾终止。

因此,只要匹配[a-z]之类的模式,就会在该匹配时剪切字符串。由于字符串中的每个字符都与模式匹配,因此结果数组为空(删除尾随空字符串)。

同样适用于\w\w+?(一个或多个\w,但重复次数尽可能少)。那个\w*?导致你期望的是*?量词所导致的东西,因为如果可能的话,它会匹配零重复,所以一个空字符串。并且在给定字符串中的每个位置都找到一个空字符串。