扫描哈希并返回值,如果为true

时间:2015-03-16 21:58:48

标签: ruby regex hash

根据我的哈希,如果它在字符串中,我想匹配它:

def conv
  str = "I only have one, two or maybe sixty"
  hash = {:one => 1, :two => 2, :six => 6, :sixty => 60 }
  str.match( Regexp.union( hash.keys.to_s ) )
end

puts conv # => <blank>

以上不起作用,但只匹配“一个”:

str.match( Regexp.union( hash[0].to_s ) )

编辑:

知道如何在字符串中匹配“one”,“two”和sixty?

如果我的字符串有“sixt”,则返回“6”,这不应该基于@Cary的答案发生。

1 个答案:

答案 0 :(得分:1)

您需要将hash.keys的每个元素转换为字符串,而不是将数组hash.keys转换为字符串,您应该使用String#scan而不是String#match。您可能还需要使用正则表达式,直到它返回您想要的任何东西,而不是您不想要的任何东西。

让我们先看看你的例子:

str = "I only have one, two or maybe sixty"
hash = {:one => 1, :two => 2, :six => 6, :sixty => 60}

我们可能会考虑在我们希望匹配的每个单词之前和之后使用分词符(\b)构建正则表达式:

r0 = Regexp.union(hash.keys.map { |k| /\b#{k.to_s}\b/ })
  #=> /(?-mix:\bone\b)|(?-mix:\btwo\b)|(?-mix:\bsix\b)|(?-mix:\bsixty\b)/

str.scan(r0)
  #=> ["one", "two", "sixty"]

如果没有单词分隔符,scan将返回["one", "two", "six"],而"sixty"中的str将匹配"six"。 (单词中断是零宽度。字符串前面的一个要求字符串前面有非单词字符或位于字符串的开头。字符串后面的字符串要求字符串后跟非单词字符或在字符串的末尾。)

根据您的要求,分词可能不够或不合适。例如,假设(上面有hash):

str = "I only have one, two, twenty-one or maybe sixty"

我们不希望匹配"twenty-one"。然而,

str.scan(r0)
  #=> ["one", "two", "one", "sixty"] 

一种选择是使用一个正则表达式,要求匹配前面有空格或位于字符串的开头,后跟空格或位于字符串的末尾:

r1 = Regexp.union(hash.keys.map { |k| /(?<=^|\s)#{k.to_s}(?=\s|$)/ })
str.scan(r1)
  #=> ["sixty"] 

(?<=^|\s)是一个积极的背后隐藏; (?=\s|$)是一个正向前瞻

嗯,这避免了"twenty-one"(好)的匹配,但我们不再匹配"one""two"(不好)因为字符串中每个单词后面都有逗号

这里的解决方案可能是首先删除标点符号,这样我们就可以应用上述正则表达式中的任何一个:

str.tr('.,?!:;-','')
  #=> "I only have one two twentyone or maybe sixty" 

str.tr('.,?!:;-','').scan(r0)
  #=> ["one", "two", "sixty"] 

str.tr('.,?!:;-','').scan(r1)
  #=> ["one", "two", "sixty"] 

您可能还希望将正则表达式末尾的/更改为/i,以使匹配对大小写不敏感。 1

对于想要了解原因&#39;被称为小写和&#39; A&#39;被称为大写