如何在Ruby中检查一个字符串是否包含任何一个字符串数组中的字符串。

5

我有一个字符串数组a,我想检查另一个长字符串b是否包含数组中的任何字符串。

a = ['key','words','to', 'check']
b = "this is a long string"

我有哪些不同的选项可以完成这个任务?

例如,以下方法似乎有效:

not a.select { |x| b.include? x }.empty?

但它返回了一个负面的响应,这就是为什么我使用了 not ,还有其他想法或不同的方法吗?

在使用andornot运算符时要小心,因为它们的优先级比赋值运算符低,应该使用&&||! - Brandon Buck
3个回答

16

你正在使用#any?方法。

a = ['key','words','to', 'check']
b = "this is a long string"
a.any? { |s| b.include? s }

或者类似使用::union这样的东西。但是根据需要,您可能需要稍微更改正则表达式。如果不行,那么我将使用上面的那个。

a = ['key','words','to', 'check'] 
Regexp.union a
# => /key|words|to|check/ 
b = "this is a long string"
Regexp.union(a) === b # => false 

2
我认为正则表达式会显著提高速度。 - DGM
@DGM - 我认为恰恰相反 - 正则表达式可能比include?慢得多... - Uri Agassi
@DGM 请继续进行基准测试。一般来说,字符串匹配比正则表达式更快,但总会有一些特殊情况。结果可能因人而异。 - Todd A. Jacobs
在这种情况下,还不错,但如果字符串长度为100k,单词列表有数百个,那么你就会面临一个n*m的问题。 - DGM

1

扫描和展平

有许多方法可以实现您想要的功能,但即使在代码变得更冗长时,我仍喜欢为清晰的目的编程。对我来说最好理解的方式是扫描字符串中的每个数组成员,然后查看展平的结果是否有任何成员。例如:

a = ['key','words','to', 'check']
b = "this is a long string"
a.map { |word| b.scan /#{word}/ }.flatten.any?
# => false

a << 'string'
a.map { |word| b.scan /#{word}/ }.flatten.any?
# => true

这个方法之所以有效,是因为scan返回一个匹配项的数组,例如:
=> [[], [], [], [], ["string"]]

Array#flatten 确保移除空的嵌套数组,这样 Enumerable#any? 才能表现出你所期望的行为。如果想要了解为什么需要 #flatten,请考虑以下示例:

[[], [], [], []].any?
# => true
[[], [], [], []].flatten.any?
# => false

@ArupRakshit 感谢您的好建议。虽然我喜欢 #flat_map,因为它可以使链条更短,但我通常更喜欢可组合的链条,以便于清晰和调试。此外,我相信 #flat_map 是在 1.9.2 中引入的,因此对于任何使用遗留 Ruby 的人可能没有用。虽然我没有进行过测试,但我很确定我的示例可以在任何版本上运行,甚至是 1.8.6,这希望能使更广泛的观众受益。个人经验可能会有所不同。 - Todd A. Jacobs

0

你也可以使用数组交集 (#&) 方法:

a = ['key','words','to', 'check']
b = "this is a long string"
shared = a & b.gsub(/[.!?,'"]/, "").split(/\s/)

这将返回一个包含所有共享字符的数组。


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