Cara membaca baris file di Ruby

238

Saya mencoba menggunakan kode berikut untuk membaca baris dari file. Tetapi ketika membaca file , isinya semua dalam satu baris:

line_num=0
File.open('xxx.txt').each do |line|
  print "#{line_num += 1} #{line}"
end

Tetapi file ini mencetak setiap baris secara terpisah.


Saya harus menggunakan stdin, seperti ruby my_prog.rb < file.txt, di mana saya tidak bisa berasumsi apa karakter akhir baris yang digunakan file. Bagaimana saya bisa mengatasinya?

seri
sumber
7
Daripada melakukannya line_num = 0, Anda bisa menggunakan each.each_with_indexatau mungkin each.with_index.
Andrew Grimm
@ andrew-grimm terima kasih, ini membuat kode lebih bersih.
gambar
Lihat stackoverflow.com/q/25189262/128421 untuk alasan mengapa IO baris demi baris lebih disukai daripada menggunakan read.
the Tin Man
Gunakan line.chompuntuk menangani ujung garis (milik @SivivivasanAC )
Yarin
Kemungkinan rangkap dari Apa saja cara umum untuk membaca file di Ruby?
Brad Werth

Jawaban:

150

Saya percaya jawaban saya mencakup kekhawatiran baru Anda tentang penanganan semua jenis akhir baris karena keduanya "\r\n"dan "\r"dikonversi ke standar Linux "\n"sebelum menguraikan baris.

Untuk mendukung "\r"karakter EOL bersama dengan reguler "\n", dan "\r\n"dari Windows, inilah yang akan saya lakukan:

line_num=0
text=File.open('xxx.txt').read
text.gsub!(/\r\n?/, "\n")
text.each_line do |line|
  print "#{line_num += 1} #{line}"
end

Tentu saja ini bisa menjadi ide buruk pada file yang sangat besar karena itu berarti memuat seluruh file ke dalam memori.

Olivier L.
sumber
Regex itu tidak berhasil untukku. Format Unix menggunakan \ n, windows \ r \ n, mac menggunakan \ n - .gsub (/ (\ r | \ n) + /, "\ n") bekerja untuk saya dalam semua kasus.
Pod
4
Regex yang benar adalah /\r?\n/yang akan mencakup \ r \ n dan \ n tanpa menggabungkan baris kosong seperti komentar Pod
Irongaze.com
12
Ini akan membaca seluruh file ke dalam memori, yang bisa mustahil tergantung pada seberapa besar file tersebut.
eremzeit
1
Metode ini sangat sangat tidak efisien, jawaban talabes di sini stackoverflow.com/a/17415655/228589 adalah jawaban terbaik. Harap verifikasi implementasi kedua metode ini.
CantGetANick
1
Ini bukan jalan ruby. Jawaban di bawah ini menunjukkan perilaku yang benar.
Merovex
525

Ruby memang memiliki metode untuk ini:

File.readlines('foo').each do |line|

http://ruby-doc.org/core-1.9.3/IO.html#method-c-readlines

Jonathan
sumber
methond ini lebih lambat daripada methond yaitu @Olivier L.
HelloWorld
1
@ HaloWorld Mungkin karena menghapus setiap baris sebelumnya dari memori dan memuat di setiap baris ke dalam memori. Mungkin salah, tetapi Ruby mungkin melakukan hal-hal dengan benar (sehingga file besar tidak menyebabkan skrip Anda mogok).
Starkers
Bisakah Anda menggunakan with_indexini juga?
Joshua Pinter
1
Ya, Anda bisa, misalnyaFile.readlines(filename).each_with_index { |line, i| puts "#{i}: #{line}" }
wulftone
Metode ini sepertinya lebih baik. Saya membaca file yang sangat besar dan dengan cara ini tidak merusak aplikasi dengan mencoba memuat seluruh file ke memori sekaligus.
Shelby S
393
File.foreach(filename).with_index do |line, line_num|
   puts "#{line_num}: #{line}"
end

Ini akan mengeksekusi blok yang diberikan untuk setiap baris dalam file tanpa menghirup seluruh file ke dalam memori. Lihat: IO :: foreach .

talabes
sumber
10
Ini adalah jawabannya - Ruby idiomatik dan tidak menyeruput file tersebut. Lihat juga stackoverflow.com/a/5546681/165673
Yarin
4
Semua memuji dewa Ruby!
Joshua Pinter
bagaimana cara menuju ke baris kedua di dalam loop?
user1735921
18

File pertama Anda memiliki akhiran garis Mac Classic (itu "\r"bukan yang biasa "\n"). Buka dengan

File.open('foo').each(sep="\r") do |line|

untuk menentukan akhir baris.

Josh Lee
sumber
1
Sayangnya, tidak ada yang seperti baris baru universal di Python, setidaknya yang saya tahu.
Josh Lee
satu pertanyaan lagi, saya harus menggunakan stdin, seperti ruby ​​my_prog.rb <file.txt, di mana saya tidak dapat mengasumsikan apa yang digunakan oleh baris yang mengakhiri file menggunakan ... Bagaimana saya bisa mengatasinya?
gambar
Jawaban Olivier tampaknya membantu, jika Anda setuju dengan memuat seluruh file ke dalam memori. Mendeteksi baris baru saat masih memindai file akan membutuhkan lebih banyak pekerjaan.
Josh Lee
7

Itu karena endline di setiap baris. Gunakan metode chomp di ruby ​​untuk menghapus garis akhir '\ n' atau 'r' di akhir.

line_num=0
File.open('xxx.txt').each do |line|
  print "#{line_num += 1} #{line.chomp}"
end
Sreenivasan AC
sumber
2
@SreenivisanAC +1 untuk chomp!
Yarin
7

Saya sebagian dengan pendekatan berikut untuk file yang memiliki header:

File.open(file, "r") do |fh|
    header = fh.readline
    # Process the header
    while(line = fh.gets) != nil
        #do stuff
    end
end

Ini memungkinkan Anda memproses baris tajuk (atau garis) secara berbeda dari garis konten.

Ron Gejman
sumber
6

bagaimana mendapat ?

myFile=File.open("paths_to_file","r")
while(line=myFile.gets)
 //do stuff with line
end
JBoy
sumber
4

Jangan lupa bahwa jika Anda khawatir tentang membaca dalam file yang mungkin memiliki garis besar yang bisa membanjiri RAM Anda saat runtime, Anda selalu dapat membaca file sepotong-makan. Lihat " Mengapa menghirup file itu buruk ".

File.open('file_path', 'rb') do |io|
  while chunk = io.read(16 * 1024) do
    something_with_the chunk
    # like stream it across a network
    # or write it to another file:
    # other_io.write chunk
  end
end
Nels
sumber