CSV解析,换行符问题。

3
我正在尝试创建一个解析器,用于多个CSV文件,并最终输出到另一个与Excel兼容的CSV文件。这些CSV文件是由商业工具导出的,该工具获取防火墙配置并向我们提供找到的任何问题的报告。
到目前为止,我已经想出了如何读取文件夹中的文件,查找特定值,确定我拥有的设备类型,然后将其输出到屏幕或CSV中,但仅当每行具有单个单元格条目时。如果源IP“单元格”(或任何其他单元格)包含多个IP,通过换行符分隔,输出会在该换行符上中断,并将其余部分推送到下一行。
我目前的代码是:
require 'csv'
require 'pp'

nipperfiles = Dir.glob(ARGV[0] + '/*.csv')

def allcsv(nipperfiles)
  filearray = []
  nipperfiles.each do |csv|
    filearray << csv
  end

  filearray
end

def devicetype(filelist)
  filelist.each do |f|
    CSV.foreach(f, :headers => true, :force_quotes => true) do |row|
      if row["Table"] =~ /audit device list/ && row["Device"] =~ /Cisco/
        return "Cisco"
      elsif row["Table"] =~ /audit device list/ && row["Device"] =~ /Dell/
        return "Sonicwall"
      elsif row["Table"] =~ /audit device list/ && row["Device"] =~ /Juniper/
        return "Juniper"
      end
    end
  end
end

def adminservices(device, filelist)
  administrative = []

  filelist.each do |f|
    CSV.foreach(f, :headers => true, :col_sep => ",", :force_quotes => true, :encoding => Encoding::UTF_8) do |row|
      if row["Table"] =~ /administrative service rule/
        if row["Dst Port"] != "Any" and row["Service"] != "[Host] Any"
          if device == "Cisco"
            administrative << row["Table"] + ',' + row["Rule"] + ',' + row["Protocol"] + ',' + row["Source"] + ',' + row["Destination"] + ',' + row["Dst Port"]
          elsif device == "Sonicwall"
            administrative << row["Table"] + ',' + row["Rule"] + ',' + row["Source"] + ',' + row["Destination"] + ',' + row["Service"]
          elsif device == "Juniper"            
            administrative << row["Table"] + ',' + row["Rule"] + ',' + row["Source"] + ',' + row["Destination"] + ',' + row["Service"]
          end
        end
      end
    end
  end
  administrative
end

def writecsv(admin)

  finalcsv = File.new("randomstorm.csv", "w+")
  finalcsv.puts("Administrative Services Table:\n", admin, "\r\n")
  finalcsv.close

end

filelist = allcsv(nipperfiles)
device = devicetype(filelist)
adminservices(device, filelist)
admin = adminservices(device, filelist)
writecsv(admin)

有没有办法让它忽略单元格内的换行符,或者我的代码很糟糕,需要重新开始?

我尝试使用CSV库编写CSV文件,但结果相同,我认为这个代码稍微清晰一些,可以演示问题。

如果有帮助,我可以对输入文件进行清理。


请分享输入文件中有问题的几行示例。 - Wand Maker
欢迎。请不要使用道别语(“非常感谢,”)或署名(“Rich”)。我们正在编写一本参考书,而不是进行讨论,因此您正在撰写有关解决您所询问问题的文章的第一部分。另外,请确认您的代码是否是演示问题所必需的最小化版本?请阅读 “[mcve]” 和 “[ask]”。 - the Tin Man
请提供最少的输入数据,以便于您的代码能够演示问题。让我们自己去想象数据并不能解决问题。请充分使用CSV类。虽然CSV不是一个很规范的格式,但是该类已经经过了非常好的测试,所以它可以处理您没有遇到或想象到的情况。 - the Tin Man
1个回答

4

只要在引号内,字段内的换行是可以的:

CSV.parse("1,\"2\n\n\",3")
=> [["1", "2\n\n", "3"]]

尝试直接将内容写入字符串或文件中,就像文档中所示,这可以确保您的包含换行符的字段被引用:
def writecsv(admin)
 csv_string = CSV.generate do |csv|
   admin.each { |row| csv << row }
 end 

 finalcsv = File.new("randomstorm.csv", "w+")
 finalcsv.puts("Administrative Services Table:\n", csv_string, "\r\n")
 finalcsv.close
end

同时确保你将字段作为数组写入adminservices()函数内:

administrative << [row["Table"], row["Rule"], row["Protocol"], row["Source"], row["Destination"], row["Dst Port"]]

Martin, 非常感谢您的回复!那个方法完美无缺。我已经为此苦苦思索了好几天,你救了我的心智。 - hatlord
1
在 Ruby 中,使用 File.open 的块形式而不是使用 File.new 是惯用的写法。 - the Tin Man

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接