考虑一下:
File.readlines('words.txt').map do |word|
array_of_words << word
end
会将整个文件读入内存,然后将其转换为数组中的单个元素。您可以使用以下方法完成同样的事情:
array_of_words = File.readlines('words.txt')
一个潜在的问题是它不可扩展。如果“words.txt”大于可用内存,您的代码就会出现问题,所以要小心。
可以通过多种方式在文件中搜索单词数组,但我一直发现使用正则表达式最容易。 Perl 有一个很棒的模块,叫做 Regexp::Assemble,它可以很容易地将单词列表转换为非常有效的模式,但是 Ruby 缺少这种功能。请参阅“Is there an efficient way to perform hundreds of text substitutions in Ruby?”了解我过去整理的一种解决方案。
Ruby 确实有 Regexp.union,但这只是部分帮助。
words = %w(foo bar)
re = Regexp.union(words) # => /foo|bar/
生成的模式具有表达式的标志,因此您必须小心将其插入另一个模式:
/#{re}/ # => /(?-mix:foo|bar)/
(?-mix: 会给你带来麻烦,所以不要那样做。而是使用:
/#{re.source}/ # => /foo|bar/
这将生成模式并按照我们预期的方式运行。
不幸的是,这也不是一个完整的解决方案,因为换句话说,这些单词可以作为子字符串找到:
'foolish'[/#{re.source}/] # => "foo"
解决这个问题的方法是围绕模式设置单词边界:
/\b(?:#{re.source})\b/ # => /\b(?:foo|bar)\b/
然后查找整个单词:
'foolish'[/\b(?:#{re.source})\b/] # => nil
更多信息请参见 Ruby 的 Regexp 文档。
一旦有了想要使用的模式,搜索就变得更简单了。 Ruby 有Find 类,它可以很容易地递归搜索目录中的文件。文档介绍了如何使用它。
或者,您可以使用Dir 类来拼凑您自己的方法。同样,它在文档中有使用它的示例,但我通常使用 Find。
读取您正在扫描的文件时,我建议使用foreach 逐行读取文件。 File.read 和File.readlines 是不可可扩展的,当 Ruby 试图将一个大文件读入内存时,它们会使你的程序行为异常。相反,foreach 将产生运行速度更快的可扩展代码。有关详细信息,请参阅“Why is "slurping" a file not a good practice?”。
使用上面的链接,您应该能够快速将一些东西组合在一起,这些东西可以高效地运行并且很灵活。
这个未经测试的代码应该可以帮助您入门:
WORD_ARRAY = File.readlines('words.txt').map(&:chomp)
WORD_RE = /\b(?:#{Regexp.union(WORD_ARRAY).source}\b)/
Dir['Source/**/*'].select{|f| File.file?(f) }.each do |filepath|
puts "#{filepath}: #{!!File.read(filepath)[WORD_RE]}"
end
它会输出它正在读取的文件,以及“真”或“假”是否在列表中找到一个单词。
由于readlines 和read,它不可扩展,如果任何文件很大,它可能会严重减速。同样,请参阅上面“slurp”链接中的注意事项。