Ruby如果......任何? ......包括?句法

时间:2017-10-29 15:52:14

标签: ruby

我需要检查一个长文本字符串中是否存在大型(60,000+元素)数组的任何元素。我目前的代码如下:

if $TARGET_PARTLIST.any? { |target_pn| pdf_content_string.include? target_pn }
  self.last_match_code = target_pn
  self.is_a_match = true
end

我收到语法错误undefined local variable or method target_pn

有人能让我知道这段代码使用的正确语法吗?此外,如果有人知道更快的方法,我全都耳朵!

3 个答案:

答案 0 :(得分:3)

在这种情况下,您的所有语法都是正确的,您只是遇到了逻辑错误。虽然target_pn在传递给any?的块内被定义(作为参数),但它没有在if语句的块中定义,因为any?的范围 - 块以结束大括号结束,而target_pn在其范围之外不可用。您的代码的正确(和更惯用)版本将如下所示:

self.is_a_match = $TARGET_PARTLIST.any? do |target_pn| 
  included = pdf_content_string.include? target_pn
  self.last_match_code = target_pn if included
  included
end

或者,正如jvillian所说的那样,可以将字符串转换为单词数组,然后进行交集并查看结果集是否为非空。像这样:

self.is_a_match = !($TARGET_PARTLIST & 
                    pdf_content_string.gsub(/[^A-Za-z ]/,"")
                                      .split).empty?

不幸的是,这种方法失去了self.last_match_code。作为塞尔吉奥指出的一个注释,如果您正在处理非英语语言,则必须更改上述正则表达式。

希望有所帮助!

答案 1 :(得分:2)

您应该使用Enumerable#find而不是Enumerable#any?

found = $TARGET_PARTLIST.find { |target_pn| pdf_content_string.include? target_pn }
if found
  self.last_match_code = found
  self.is_a_match = true
end

请注意,这并不能确保字符串包含一个$TARGET_PARTLIST元素的单词。例如,如果$TARGET_PARTLIST包含单词" able",则该字符串将在字符串中找到,"您觉得舒服吗?"。如果您只想匹配单词,则可以执行以下操作。

found = $TARGET_PARTLIST.find { |target_pn| pdf_content_string[/\b#{target_pn}\b/] }

请注意,这使用方法String#[]

\b是正则表达式中的单词中断,这意味着匹配的第一个(最后一个)字符不能在单词字符(字母,数字)之前(后跟)出现或者下划线)。

如果速度很重要,使用以下内容可能会更快。

found = $TARGET_PARTLIST.find { |target_pn|
  pdf_content_string.include?(target_on) && pdf_content_string[/\b#{target_pn}\b/] }

答案 2 :(得分:0)

一种可能更高效的方法是让Regexp搜索它,将所有这些转移到本机代码中。

# needed only once
TARGET_PARTLIST_RE = Regexp.new("\\b(?:#{$TARGET_PARTLIST.sort.map { |pl| Regexp.escape(pl) }.join('|')})\\b")

# to check
self.last_match_code = pdf_content_string[TARGET_PARTLIST_RE]
self.is_a_match = !self.last_match_code.nil?

更高效的方法是构建前缀树并使用前缀树创建正则表达式(这会优化正则表达式查找),但这需要更多工作:)