Ruby的“hello world”.scan(/(\w){2}/)与“hello world”.scan(/\w{2}/)不同吗?

3

我曾认为我了解 Ruby 中的 scan:它只是执行单次匹配,然后重复此过程以获取所有结果并将其放入数组中?

ruby-1.9.2-p0 > "hello world".scan(/\w{2}/)
 => ["he", "ll", "wo", "rl"] 

ruby-1.9.2-p0 > "hello world".scan(/(\w){2}/)
 => [["e"], ["l"], ["o"], ["l"]] 

为什么第二行会得到那个结果,如何使其返回与第一行相同的结果?(因为有时我们必须在正则表达式中添加 ()。)


作为一个约定,以下两种写法是等价的:

ruby-1.9.2-p0 > "hello world"[/\w{2}/]
 => "he" 

ruby-1.9.2-p0 > "hello world"[/(\w){2}/]
 => "he" 
2个回答

3

圆括号创建了一个匹配组。请尝试使用/(?:\w){2}/


1
这个是如何解释OP所说的行为的呢?我完全不明白... - Tim Pietzcker
1
@Tim:它正在显示分组,但实际上只有最后一个匹配项(即每两个字母中的第二个字母)被分组。修复方法就是不进行分组。 - Ignacio Vazquez-Abrams
@Ignacio 你的意思是 ?: 不会创建一个组吗?这只是 Ruby 特有的吗?有没有更简单的解决方案...比如其他方法,或者 "hello world"[/\w{2}/g] ... 或者 "hello world".scan(/(\w){2}/, :top_level)...一些更简单的形式。 - nonopolarity
非分组匹配通过 (?:...) 在许多现代正则表达式引擎中被发现。至于可能更简单的解决方案,我不了解足够的 Ruby 以便给出任何建议。 - Ignacio Vazquez-Abrams
1
@Tim 我认为 OP 中的第二行是给出了“最终”匹配的 ( ) 内容... 因此它忽略了顶层匹配并使用了被匹配两次的 ( ) 并使用了第二个。 - nonopolarity
啊,我懂了。如果有一个组,那么scan在正则表达式中的行为显然会与没有组时有所不同。谢谢! - Tim Pietzcker

0
我发现了更多的东西:
如果有任何分组,scan 似乎会使用它们,这就是第二行的行为方式。 (在数组结果中使用括号内最后匹配的内容。)
作为一个测试:(如果有多个组,则所有组都进入一个数组)
ruby-1.9.2-p0 > "hello world".scan(/((\w){2})/)
 => [["he", "e"], ["ll", "l"], ["wo", "o"], ["rl", "l"]] 

这是一种获取它的方法:始终添加顶级 ( ),并使用 map 获取数组中的第一个元素(即顶级匹配):
ruby-1.9.2-p0 > "hello world".scan(/((\w){2})/).map {|e| e.first}
 => ["he", "ll", "wo", "rl"]

但我仍然希望找到更简单的答案...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接