当其中一列包含双引号“字符”时,我该如何解析CSV文件?我收到“第xxx行缺少或丢失引号”错误,因为其中有一个尾随的双引号。确切的错误是“第58行缺少或丢失引号(CSV::MalformedCSVError)”。数据来自解析另一个设备(防火墙)配置的应用程序,并且“已被管理员作为注释添加到此设备的配置中,因此超出了我的控制范围。”
示例输入数据(无法提供文件,它们本质上是敏感的):
"Table 1 Firewall Policy from INT to EXT administrative service rules on TestFirewall","1","Yes","Allow","[Group] GreenServer","[Host] Any","[Group] FTP","No",""Access"^M正如您所看到的,最后一列中的注释是""Access“”。如果最后一列中只有一个双引号,那么到目前为止,我的脚本似乎工作得很好。
复制所需的最低代码:
#!/usr/bin/env ruby
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, :encoding => Encoding::UTF_8) do |row|
if row["Table"] =~ /audit device list/ && row["OS"] =~ /FortiOS/
return "Fortigate"
end
end
end
end
filelist = allcsv(nipperfiles)
device = devicetype(filelist)理想情况下,正常工作的代码将忽略额外的引号或替换它或任何其他潜在的有问题的字符。可能值得注意的是,考虑到最初的防火墙配置是由一个人配置的,该人可以将额外的引号放在几乎任何单元格/字段中。
发布于 2016-02-08 00:17:09
这里有一个技巧可能会有所帮助。使用:quote_char => "'" (假设CSV中的列中的值没有单引号字符),这将在读取的值中包含双引号-您可以通过代码删除双引号:
示例:
CSV.foreach(f, :force_quotes => true, :encoding => Encoding::UTF_8,
:quote_char => "'") do |row|
puts row[0]
#=> "Table 1 Firewall ... administrative service rules on TestFirewall"
puts row[0][1..-2]
#=> Table 1 Firewall ... administrative service rules on TestFirewall
end仅供参考:您可以使用CSV文本中最不可能出现的任何字符作为:quote_char,上面的解决方案仍然有效
如果上面不起作用,那么您最好将每一行都作为字符串处理,并对其使用split,而不是使用CSV类。
File.open("/path/to/file") do |f|
f.each_line do |for|
columns = row.split(",")
end
end发布于 2016-02-08 01:19:45
您可以从CSV::MalformedCSVError中解救出来,并为有此类问题的行创建单独的处理程序,但这意味着您必须单独解析每一行,并且您将丢失标题行中的列名。
require 'csv'
File.open('csv.csv').each_line do |input_row|
begin
CSV.parse(input_row) do |row|
puts row.inspect
end
rescue CSV::MalformedCSVError => error
if input_row.include?('""')
input_row.gsub!('""', '"')
retry
else
raise error
end
end
end我有点惊讶,没有像:on_malformed_csv => lambda ...这样的选择。
发布于 2016-02-08 23:25:22
Tin Man的想法被证明是最好的,基本上读取了所有的文件,更改了我不想要的部分。该脚本随后写入可由CSV类读取的已清理文件。这允许我在需要的时候添加更多的替换。
我选择使用the Rio gem来完成工作。
代码的基本思想:
cleanme = Dir.glob(ARGV[0])
def cleanfiles(cleanme)
puts "Cleaning up CSV files"
rio(cleanme).all.files('*.csv') do |f|
puts "Reading and Cleaning File: #{f}"
rio(f) <f.contents.gsub("''", "Empty").gsub(/""\w+"/, '"Comment Malformed and Removed"').gsub("\r\n", "\r")
end
end只要有格式错误的注释抛出错误,我就用“注释格式错误并删除”行替换为错误的引号。这允许我的团队中的人交叉引用原始输入文件,并找出注释应该是什么。任何空字段(技术上是"''")都会被字符串" empty“替换。
https://stackoverflow.com/questions/35255668
复制相似问题