0

我正在尝试读取 Rails 中上传文件的每一行。

file_data = params[:files]
    if file_data.respond_to?(:read)
      file_data.read.gsub( /\n/, "\r\n" ).split("\r\n").each do |line|
        inputUsers.push(line.strip)
      end
    elsif file_data.respond_to?(:path)
      File.read(file_data.path).gsub( /\n/, "\r\n" ).split("\r\n").each do |line|
       inputUsers.push(line.strip)
     end

如果上传的文件包含 Windows 和 Unix 编码的混合,可能是由于从多个地方复制,Rails 不会正确分隔文件的每一行,有时会返回两行作为一个。

该应用程序托管在 Linux 机器上。此外,该文件是从 Google 文档电子表格列中复制的。

这个问题有什么解决方案吗?


编辑:

未分隔成新行的行的十六进制代码如下所示:

636f 6d0d 0a4e 6968
4

3 回答 3

2

这就是我将如何解决这个问题。首先,测试一些代码:

SAMPLE_TEXT = [
  "now\ris\r\nthe\ntime\n",
  "for all good men\n"
]

def read_file(data)
  data.each do |li|                       
    [ *li.split(/[\r\n]+/) ].each do |l|  
      yield l                             
    end                                   
  end                                     
end

read_file(SAMPLE_TEXT) do |li|
  puts li                       
end                             

哪个输出:

now
is
the
time
for all good men

魔法发生在[ *li.split(/[\r\n]+/) ]. 分解它:

  • li.split(/[\r\n]+/)导致该行在返回、换行和它们的组合上被拆分。如果一行有多个代码将吞噬空行,因此如果您有机会收到那些您将需要更复杂的模式/[\r\n]{1,2}/,虽然未经测试,但应该可以工作。
  • *li.split(/[\r\n]+/)使用“splat”运算符*将以下数组分解为其组成元素。当您不确定是否将单个元素或数组传递给方法时,这是一种获取数组的便捷方式。
  • [*li.split(/[\r\n]+/)]获取返回的组件并将它们转换回单个数组。

要修改处理文件的方法很容易:

def read_file(fname)
  File.foreach(fname) do |li|
    [ *li.split(/[\r\n]+/) ].each do |l|
      yield l
    end
  end
end

调用它的方式与前面的示例几乎相同:

read_file('path/to/file') do |li|
  puts li                       
end                             

您要使用的原因foreach是它会逐行读取,这比使用 slurping 文件的内存效率要高得多reador readlines,其中任何一种都可以一次将整个文件读入内存。foreach速度也非常快,因此您在使用时不会受到速度影响。因此,read使用 -type 方法几乎没有优势,而使用foreach.

于 2013-09-24T16:46:29.840 回答
1

您正在替换\n\r\n,这在解析 Windows 文件时会出现问题。现在\r\n变成\r\r\n.

更好的是替换为 Unix 行结束格式,然后拆分\n

file_data.read.gsub( /\n/, "\r\n" ).split("\r\n").each do |line|

变成:

file_data.read.gsub( /\r\n/, "\n" ).split("\n").each do |line|
于 2013-09-24T14:41:33.110 回答
0

尝试内置方法:

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

或者:

File.open('foo').read.gsub(/\r\n?/, "\n").each_line do |line|
于 2013-09-24T15:22:37.403 回答