【发布时间】:2011-05-14 15:37:31
【问题描述】:
谁能解释我如何在 Ruby 中使用正则表达式来只返回字符串的匹配项。
例如,如果代码读入一个包含一系列名称的 .txt 文件:
John Smith
James Jones
David Brown
Tom Davidson
etc etc
..并且要匹配的单词输入为“ohn”,然后它只会返回“John Smith”,但不会返回其他名称。
【问题讨论】:
谁能解释我如何在 Ruby 中使用正则表达式来只返回字符串的匹配项。
例如,如果代码读入一个包含一系列名称的 .txt 文件:
John Smith
James Jones
David Brown
Tom Davidson
etc etc
..并且要匹配的单词输入为“ohn”,然后它只会返回“John Smith”,但不会返回其他名称。
【问题讨论】:
注意:在现代红宝石中,不要使用File.each_line,而是使用IO.foreach。例如:
[1] pry(main)> IO.foreach('./.bashrc') do |l|
[1] pry(main)* puts l
[1] pry(main)* end
export PATH=~/bin:$PATH
export EDITOR='vi'
export VISUAL=$EDITOR
进步发生了,事情发生了变化。
这里有一些不同的方法可以帮助您到达目的地。
首先请注意,我使用一种更惯用的方式来编写从文件中读取行的代码。 Ruby 的 IO 和 File 库使打开、读取和关闭文件变得非常容易,并且封装在一个漂亮整洁的包中。
File.each_line('file.txt') do |li|
puts li if (li['ohn'])
end
这会在行中的任何位置查找“ohn”,但不会使用正则表达式。
File.each_line('file.txt') do |li|
puts li if (li[/ohn/])
end
它寻找相同的字符串,只是它使用正则表达式到达那里。功能上和第一个例子一样。
File.each_line('file.txt') do |li|
puts li if (li[/ohn\b/])
end
这是查找以“ohn”结尾的名称的一种更智能的方法。它使用正则表达式,但也指定模式必须出现在单词的末尾。 \b 表示“字边界”。
此外,在读取文件时,务必提前考虑正在读取的文件是否会超过您的应用可用的 RAM。一次将整个文件读入内存很容易,然后从 RAM 中处理它,但如果超出可用的物理 RAM,您可能会削弱或终止您的应用程序或机器。
您是否知道其他答案显示的代码实际上是将整个文件加载到 RAM 中,还是通过从 readlines 函数流式传输到 select 函数以某种方式进行了优化?
来自IO#readlines 文档:
读取由名称指定的整个文件作为单独的行,并在数组中返回这些行。行由 sep 分隔。
另外一个考虑因素是在大批量读取期间的内存分配。即使您有足够的 RAM,您也可能会遇到这样的情况:一种语言在读取数据时阻塞,发现它没有为变量分配足够的内存,并且在获取更多内存时不得不暂停。该循环一直重复,直到加载整个文件。
多年前,当我将一个非常大的数据文件加载到我管理的 HP 最大的 mini 上的 Perl 应用程序中时,我对此变得敏感。该应用程序会定期暂停几秒钟,我不知道为什么。我进入调试器并找不到问题。最后,通过使用老式打印语句跟踪运行,我将暂停隔离到文件“slurp”。我有足够的 RAM 和足够的处理能力,但是 Perl 没有分配足够的内存。我切换到逐行阅读,应用程序快速完成了处理。 Ruby 与 Perl 一样,具有良好的 I/O,并且在逐行读取时可以非常快速地读取大文件。我从来没有找到一个使用文本文件的好理由,除非我希望内容可以分布在多行中,但这并不常见。
【讨论】:
readlines 函数流式传输到 select 函数以某种方式进行了优化?
readlines 的答案都是将整个文件加载到内存中。它是一个数组,但它在内存中。
each_line 不是File 的类方法。您需要先打开一个文件。
也许我没有完全理解这个问题,但你可以这样做:
File.readlines("path/to/file.txt").select { |line| line =~ /ohn/ }
获取符合条件的所有行的数组。
【讨论】:
query = 'ohn'
names = File.readlines('names.txt')
matches = names.select { |name| name[/#{query}/i] }
#=> ["John Smith"]
如果您希望查询区分大小写,请删除正则表达式末尾的 i。
【讨论】:
老问题,但Array#grep 也可用于搜索字符串列表
File.readlines("names.txt").grep /#{query}/i
【讨论】: