解析文本文件并以新格式输出

时间:2015-01-16 22:40:43

标签: ruby sorting

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

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

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

pipe.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

comma.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

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

2 个答案:

答案 0 :(得分:0)

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

我写了

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 <=> b }相同的块,以便冗余而不需要。

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

ary = [
  'a b',
  'a  b'
].sort 

ary # => ["a  b", "a b"]

从表面上看,似乎'a b''a b'或之后相同,但是,因为' '的ASCII值低于b,{{ 1}}在'a b'

之前结束整理
'a b'

查看实际值:

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

那么,这就是为什么我们要将线条划分为它们的值,以否定分隔符的效果。

继续前进,分割线条并不是你想要在&#34;通用&#34;中做的事情。方法,尽管你可以。而且,我不打算为你写一切,但我会指出方向。

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

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

现在可以将行拆分成组件字段,事情应该有效:

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。由你决定如何做到这一点。

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

map(&:strip)

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

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

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"]]

答案 1 :(得分:0)

最简单的方法是使用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个对象被反转以获得您需要的相反顺序