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

问题描述:

我正在学习正则表达式,并认为我已经开始掌握了。但后来......拆分字符串与正则表达式 w w *? w +?

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

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 * ?,(问号防止贪婪)按我的预期工作,在每个字符上分割字符串。星号,零个或多个匹配项返回一个空数组。

我已经试过内记事本+ +,并在节目中表达,它显示了5场比赛,如:基本

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

Output is: a b c d e 

这真的让我为难,

+0

我不能相信你会被分配到Java的正则表达式作业,而不是使用不需要的语言\\ dd \\ oo \\ uu \\ bb \\ ll \\ ee \\ \\ bb \\ AA \\立方厘米\\ KK \\ SS \\ LL \\ AA \\ SS \\ HH \\ EE \\ SS !!什么酷刑!另外你甚至没有编译时检查正则表达式的语法,也没有调试等等等等。Java对于这类工作并不是很方便。你应该用更加同情的语言来开发你的正则表达式,然后把最终结果传给Java。 – tchrist 2012-03-18 19:04:47

+0

@tchrist你在想什么语言? – Kennet 2012-03-19 08:29:32

+0

除了像sed和awk这样的shell工具之外,Perl和Ruby还有第一类正则表达式,甚至Python也可以让你跳过双击页面。 Perl是唯一一个使用正则表达式调试器的人。 – tchrist 2012-03-19 13:22:35

如果用正则表达式分割字符串,告诉哪里应该切断字符串。这必然会削减你与正则表达式匹配的东西。这意味着如果你在\w处分割,那么每个字符都是一个分割点,它们之间的子串(全部为空)将被返回。 Java会自动删除尾随的空字符串,如the documentation中所述。

这也解释了为什么懒惰匹配\w*?会给你每个字符,因为它会匹配任何字符(零宽度)之间(以及之前和之后)的每个位置。剩下的是字符串本身的字符。

让我们来分析一下:

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

    你的字符串是

    abcde 
    

    而且MATC HES如下:

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

    这让您与子比赛之间,所有这一切都是空的。

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

  2. \w*?

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

    在这种情况下比赛是人物之间,让你用下面的字符串:

    "", "a", "b", "c", "d", "e", "" 
    

    的Java抛出后空单了,虽然。

+1

Java的'split'抛弃了尾部空字段,因为它模仿了Perl的'split',这就是它的原因。在这两种语言中,你可以通过在'-1'的'split'中添加另一个参数来抑制这种行为。 – tchrist 2012-03-18 19:06:13

String.split切割串在图案中的每个匹配:

通过此方法返回的数组中包含该字符串由另一个子匹配给定表达或终止终止的每个子在字符串的末尾。

因此,只要像[a-z]这样的模式匹配,字符串就会在该匹配处被剪切。由于字符串中的每个字符都与该模式匹配,所以得到的数组是空的(删除尾随空字符串)。

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

+0

这也是有帮助的,谢谢! – Kennet 2012-03-18 18:44:20

我们将每个电话分解为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)再次尝试这些示例,您应该看到所有空字符串。

+0

我也想接受你的答案,谢谢你的帮助! – Kennet 2012-03-18 18:43:06

+0

@Kennet:当然,请考虑提高你认为有帮助的答案。 – maerics 2012-03-18 18:47:57