【问题标题】:Finding lines in a text file matching a regular expression在文本文件中查找与正则表达式匹配的行
【发布时间】:2011-05-14 15:37:31
【问题描述】:

谁能解释我如何在 Ruby 中使用正则表达式来只返回字符串的匹配项。

例如,如果代码读入一个包含一系列名称的 .txt 文件:

John Smith
James Jones
David Brown
Tom Davidson
etc etc

..并且要匹配的单词输入为“ohn”,然后它只会返回“John Smith”,但不会返回其他名称。

【问题讨论】:

    标签: ruby regex


    【解决方案1】:

    注意:在现代红宝石中,不要使用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,并且在逐行读取时可以非常快速地读取大文件。我从来没有找到一个使用文本文件的好理由,除非我希望内容可以分布在多行中,但这并不常见。

    【讨论】:

    • +1 用于考虑内存。您是否知道其他答案显示的代码实际上是将整个文件加载到 RAM 中,还是通过从 readlines 函数流式传输到 select 函数以某种方式进行了优化?
    • @JasonM,任何建议使用readlines 的答案都是将整个文件加载到内存中。它是一个数组,但它在内存中。
    • each_line 不是File 的类方法。您需要先打开一个文件。
    【解决方案2】:

    也许我没有完全理解这个问题,但你可以这样做:

    File.readlines("path/to/file.txt").select { |line| line =~ /ohn/ }
    

    获取符合条件的所有行的数组。

    【讨论】:

      【解决方案3】:
      query = 'ohn'
      names = File.readlines('names.txt')
      matches = names.select { |name| name[/#{query}/i] }
      #=> ["John Smith"]
      

      如果您希望查询区分大小写,请删除正则表达式末尾的 i

      【讨论】:

        【解决方案4】:

        老问题,但Array#grep 也可用于搜索字符串列表

        File.readlines("names.txt").grep /#{query}/i
        

        【讨论】:

          猜你喜欢
          • 2020-03-05
          • 1970-01-01
          • 1970-01-01
          • 2013-02-21
          • 1970-01-01
          • 2015-04-29
          • 2020-03-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多