ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Ruby 中读取文件的行

我试图使用以下代码从文件中读取行。但是在读取 file 时,内容都在一行中:

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

但是这个 file 分别打印每一行。

我必须使用标准输入,例如 ruby my_prog.rb < file.txt,我不能假设文件使用的行尾字符是什么。我该如何处理?

除了使用 line_num = 0,您还可以使用 each.each_with_index 或可能使用 each.with_index
@andrew-grimm 谢谢,它使代码更简洁。
请参阅 stackoverflow.com/q/25189262/128421,了解为什么逐行 IO 优于使用 read
使用 line.chomp 处理行尾(由 @SreenivasanAC 提供)

I
Iulian Onofrei

Ruby 确实有一个方法:

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

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


这个方法比@Olivier L 的方法慢。
@HelloWorld 可能是因为它正在从内存中删除前一行并将每一行加载到内存中。可能是错误的,但 Ruby 可能会正确处理(因此大文件不会导致脚本崩溃)。
您也可以使用 with_index 吗?
是的,您可以,例如 File.readlines(filename).each_with_index { |line, i| puts "#{i}: #{line}" }
这种方法似乎更好。我正在读取非常大的文件,这样它就不会通过尝试一次将整个文件加载到内存中来使应用程序崩溃。
i
ihaztehcodez
File.foreach(filename).with_index do |line, line_num|
   puts "#{line_num}: #{line}"
end

这将为文件中的每一行执行给定的块,而不会将整个文件放入内存中。请参阅:IO::foreach


这就是答案 - 惯用的 Ruby 并且不会破坏文件。另请参阅stackoverflow.com/a/5546681/165673
向红宝石众神致敬!
如何转到循环内的第二行?
您必须使用 'filename' 而不是 filename。也使用 line_num+1 而不是 line_num,因此第一行从 1 开始,而不是在 0
@Smeterlink filename 是一个包含 'xxx.txt' 等字符串的变量。
t
the Tin Man

我相信我的回答涵盖了您对处理任何类型的行尾的新担忧,因为 "\r\n""\r" 在解析行之前都转换为 Linux 标准 "\n"

要支持 "\r" EOL 字符以及 Windows 中的常规 "\n""\r\n",我将执行以下操作:

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

当然,这对于非常大的文件可能不是一个好主意,因为这意味着将整个文件加载到内存中。


那个正则表达式对我不起作用。 Unix 格式使用 \n,windows \r\n,mac 使用 \n - .gsub(/(\r|\n)+/,"\n") 在所有情况下都适用于我。
正确的正则表达式应该是 /\r?\n/ 它将涵盖 \r\n 和 \n 而不会像 Pod 的评论那样组合空行
这会将整个文件读入内存,这取决于文件的大小,这可能是不可能的。
这种方法效率非常低,这里的talabes回答stackoverflow.com/a/17415655/228589是最好的答案。请验证这两种方法的实现。
这不是红宝石方式。下面的答案显示了正确的行为。
J
Josh Lee

您的第一个文件具有 Mac Classic 行尾(即 "\r" 而不是通常的 "\n")。打开它

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

指定行尾。


可悲的是,至少我所知道的 Python 中没有通用换行符。
还有一个问题,我必须使用标准输入,比如 ruby my_prog.rb < file.txt,我不能假设文件使用的行结尾字符是什么......我该如何处理?
如果您可以将整个文件加载到内存中,Olivier 的回答似乎很有帮助。在扫描文件的同时检测换行符需要更多的工作。
R
Ron Gejman

对于具有标题的文件,我偏爱以下方法:

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

这允许您以不同于内容行的方式处理标题行(或行)。


S
Sreenivasan AC

这是因为每一行都有结束线。使用 ruby 中的 chomp 方法删除末尾的结束行 '\n' 或 'r'。

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

@SreenivasanAC +1 大吃一顿!
J
JBoy

gets 怎么样?

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

C
Community

不要忘记,如果您担心读取的文件可能包含可能在运行时占用您的 RAM 的大行,您可以随时读取文件。请参阅“Why slurping a file is bad”。

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