【问题标题】:Parse through txt files and output them in new format解析txt文件并以新格式输出
【发布时间】:2015-01-16 22:40:43
【问题描述】:

我有几个 txt 文件,我需要能够用三种不同的输出解析它们:

  • 输出 1 - 按性别(女性在男性之前)然后按姓氏升序排序。
  • 输出 2 - 按出生日期升序排序。
  • 输出 3 - 按姓氏降序排列。

这是所有三个文本文件的示例:

管道.txt:

Smith | Steve | D | M | Red | 3-3-1985
Bonk | Radek | S | M | Green | 6-3-1978
Bouillon | Francis | G | M | Blue | 6-3-1975

逗号.txt:

Abercrombie, Neil, Male, Tan, 2/13/1943
Bishop, Timothy, Male, Yellow, 4/23/1967
Kelly, Sue, Female, Pink, 7/12/1959

space.txt:

Kournikova Anna F F 6-3-1975 Red
Hingis Martina M F 4-2-1979 Green
Seles Monica H F 12-2-1973 Black

我可以通过这样写来按字母顺序排列 pipe.txt:

pipe = File.open('pipe.txt', 'r') 
alpha = pipe.sort { |a, b| a <=> b }
puts alpha

我没有运气弄清楚其他任何事情。任何帮助将不胜感激。

【问题讨论】:

    标签: ruby sorting


    【解决方案1】:

    首先,您的示例代码可能有效,但您不想依赖它。

    我会写

    pipe = File.open('pipe.txt', 'r') 
    alpha = pipe.sort { |a, b| a <=> b }
    puts alpha
    

    作为:

    alpha = File.readlines('pipe.txt').sort
    

    不同之处在于使用open 并对句柄进行排序会使文件句柄保持打开状态。悬空文件句柄会消耗系统上所有可用的句柄,从而导致长时间运行的任务出现问题,因此请养成使用方法或构造的习惯,这些方法或构造会在文件完成后自动关闭文件,或者确保明确关闭文件.使用readlines 会自动返回一个行数组,并在完成读取时关闭文件。然后将该数组传递给sort

    sort 将自动使用与{ |a, b| a &lt;=&gt; b } 相同的块,因此这是多余的,不需要。

    您的代码按整个字符串排序,但这并不是您真正想要的。相反,您必须将行分成组件列,然后按这些列排序。考虑一下:

    ary = [
      'a b',
      'a  b'
    ].sort 
    
    ary # => ["a  b", "a b"]
    

    从表面上看,'a b' 似乎与'a b' 或之后相同,但由于' ' 的ASCII 值低于b'a b' 最终在'a b' 之前进行排序:

    ' '.ord # => 32
    'b'.ord # => 98
    

    查看实际值:

    'a b'.chars.map(&:ord)  # => [97, 32, 98]
    'a  b'.chars.map(&:ord) # => [97, 32, 32, 98]
    

    所以,这就是为什么我们要将行拆分为它们的值,以消除分隔符的影响。

    继续说,分割线并不是你想在“通用”方法中做的事情,尽管你可以。而且,我不打算为你写这一切,但我会指出方向。

    "comma.txt" 可以使用内置的CSV 库进行干净的解析。 “CSV”代表“逗号分隔值”。该文档已经有一个示例显示如何从文件或字符串中解析行。我使用的是字符串版本,但您想修改它以使用文件版本。作为一个开始测试,这表明我们可以对子数组进行排序并获得所需的结果:

    text = 'a,b,c
    a,a,b
    a,a,a
    '
    
    require 'csv'
    
    ary = []
    CSV.parse(text) do |row|
      ary << row
    end
    
    ary.sort
    # => [["a", "a", "a"], ["a", "a", "b"], ["a", "b", "c"]]
    

    现在可以将行拆分为组件字段,一切正常:

    text = 'Abercrombie, Neil, Male, Tan, 2/13/1943
    Bishop, Timothy, Male, Yellow, 4/23/1967
    Kelly, Sue, Female, Pink, 7/12/1959
    '
    
    require 'csv'
    
    ary = []
    CSV.parse(text) do |row|
      ary << row
    end
    
    ary.sort
    # => [["Abercrombie", " Neil", " Male", " Tan", " 2/13/1943"],
    #     ["Bishop", " Timothy", " Male", " Yellow", " 4/23/1967"],
    #     ["Kelly", " Sue", " Female", " Pink", " 7/12/1959"]]
    

    请注意,这些字段保留了它们的前导空格。您可以在各个字段上使用strip 来删除前导和尾随空格,或者map(&amp;:strip)。如何做到这一点由您自己决定。

    处理pipes.txt几乎一样,只需要告诉CSV如何解释列:

    text = 'Smith | Steve | D | M | Red | 3-3-1985
    Bonk | Radek | S | M | Green | 6-3-1978
    Bouillon | Francis | G | M | Blue | 6-3-1975
    '
    
    require 'csv'
    
    ary = []
    CSV.parse(text, col_sep: '|') do |row|
      ary << row
    end
    
    ary.sort
    # => [["Bonk ", " Radek ", " S ", " M ", " Green ", " 6-3-1978"],
    #     ["Bouillon ", " Francis ", " G ", " M ", " Blue ", " 6-3-1975"],
    #     ["Smith ", " Steve ", " D ", " M ", " Red ", " 3-3-1985"]]
    

    同样,空格被保留,只是现在它们是尾随空格。而且,你还要弄清楚如何处理它们。

    处理 text.txt 可能是最直接的:

    text = 'Kournikova Anna F F 6-3-1975 Red
    Hingis Martina M F 4-2-1979 Green
    Seles Monica H F 12-2-1973 Black
    '
    
    ary = text.split("\n").map { |row|
      row.split
    }
    puts ary.map{ |r| r.join(',') }
    
    # >> Kournikova,Anna,F,F,6-3-1975,Red
    # >> Hingis,Martina,M,F,4-2-1979,Green
    # >> Seles,Monica,H,F,12-2-1973,Black
    
    ary.sort
    # => [["Hingis", "Martina", "M", "F", "4-2-1979", "Green"],
    #     ["Kournikova", "Anna", "F", "F", "6-3-1975", "Red"],
    #     ["Seles", "Monica", "H", "F", "12-2-1973", "Black"]]
    

    【讨论】:

      【解决方案2】:

      使用 csv 格式并让库将数据解析为单独的字段是最简单的。

      这是一个示例脚本,显示您的 3 个排序顺序

      require 'csv'
      require 'date'
      
      data = CSV.parse(DATA)
      
      SurnameIndex = 0
      GenderIndex  = 2
      DateIndex    = 4
      
      puts "By gender then surname: %s" % data.sort_by.sort_by { |object| [ object[GenderIndex], object[SurnameIndex] ] }.inspect
      puts "By birth date: %s" % data.sort_by.sort_by { |object| Date.strptime(object[DateIndex], '%m/%d/%Y') }.inspect
      puts "By surname descending: %s" % data.sort_by.sort { |a, b| b[SurnameIndex] <=> a[SurnameIndex] }.inspect
      
      __END__
      Abercrombie,Neil,Male,Tan,2/13/1943
      Bishop,Timothy,Male,Yellow,4/23/1967
      Kelly,Sue,Female,Pink,7/12/1959
      

      请注意,最后一个排序将 ab 对象反转以获得您需要的相反顺序

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        • 1970-01-01
        相关资源
        最近更新 更多