Ruby程序没有读取文件中的所有行

时间:2016-05-22 18:27:08

标签: ruby io

我是ruby的新手,并且有以下代码读取文件,然后将符号分隔为“|”登录Struc数据类型的不同属性:

Song = Struct.new(:title, :name, :length)
song_file = File.new("songdata.txt")
songs = []

song_file.each_line do |line|
    file, length, name, title = line.chomp.split(/\s*\|\s*/)
    songs << Song.new(title, name, length)
end

p songs

文件songdata.txt包含以下txt:

/jazz/j00132.mp3  | 3:45 | Fats     Waller     | Ain't Misbehavin'
/jazz/j00319.mp3  | 2:58 | Louis    Armstrong  | Wonderful World
/bgrass/bg0732.mp3| 4:09 | Strength in Numbers | Texas Red

但是,当我去打印阵列歌曲时,它只包含文本文件的第一行。有关为什么会这样的想法?

4 个答案:

答案 0 :(得分:1)

问题应该与行结尾有关。 Ruby似乎可以正确地处理Windows和Unix行结尾,但只有在您将文件的行结束更改为OSX时才会读取第一行(&#34; Mac OS 9&#34;在SublimeText中)

songdata.txt的行结尾更改为Unix或Windows。

答案 1 :(得分:0)

试试这个

arr = []
File.open('songdata.txt', 'r') do |song_file|
    song_file.each_line do |detail|
      arr =  detail.split(' | ')
      title = arr[0].split(/\s*\|\s*/)
      length = arr[1]
      artist = arr[2]
      name = arr[3]
      #now you can do anything as per requirement
    end
end

答案 2 :(得分:0)

看起来这个问题是由于行结尾造成的。我发布此信息只是为了向您展示如何在此用例中使用map。它还使用__END__DATA在单个ruby脚本中混合ruby代码和测试数据。适合测试此类案例。

Song = Struct.new(:title, :name, :length)
song_file = DATA

songs = song_file.each_line.map do |line|
    file, length, name, title = line.chomp.split(/\s*\|\s*/)
    Song.new(title, name, length)
end

p songs.size
__END__
/jazz/j00132.mp3  | 3:45 | Fats     Waller     | Ain't Misbehavin'
/jazz/j00319.mp3  | 2:58 | Louis    Armstrong  | Wonderful World
/bgrass/bg0732.mp3| 4:09 | Strength in Numbers | Texas Red

通过使用map,您可以避免在迭代文件之前定义空数组。

答案 3 :(得分:0)

正如之前所说过的类似问题,您可能不应该自己进行解析,而是使用CSV库为您完成。 CSV =逗号分隔值,但支持除逗号以外的分隔符,并且管道很常见。

Ruby有一个内置的CSV库,使用它,您可以使用以下代码比较您的方法和CSV方法的结果:

#!/usr/bin/env ruby

Song = Struct.new(:title, :name, :length)
SONG_FILESPEC = 'songdata.txt'

def read_records_regex  # OP's original approach
  songs = []
  File.new(SONG_FILESPEC).each_line do |line|
      file, length, name, title = line.chomp.split(/\s*\|\s*/)
      songs << Song.new(title, name, length)
  end
  songs
end

require 'csv'
def read_records_csv  # alternate CSV approach
  songs = []
  CSV.foreach(SONG_FILESPEC, col_sep: '|') do |fields|
    fields.map!(&:strip)
    file, length, name, title = fields
    songs << Song.new(title, name, length)
  end
  songs
end

puts read_records_regex
puts '-' * 79
puts read_records_csv

输出:

#<struct Song title="Ain't Misbehavin'", name="Fats     Waller", length="3:45">
#<struct Song title="Wonderful World", name="Louis    Armstrong", length="2:58">
#<struct Song title="Texas Red", name="Strength in Numbers", length="4:09">
-------------------------------------------------------------------------------
#<struct Song title="Ain't Misbehavin'", name="Fats     Waller", length="3:45">
#<struct Song title="Wonderful World", name="Louis    Armstrong", length="2:58">
#<struct Song title="Texas Red", name="Strength in Numbers", length="4:09">

请注意,如果要丢弃数据文件,则该文件可能不应有空格。

有些CSV内核比Ruby的内置支持更复杂,但这种情况很简单,Ruby很好。