首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当单元格/字段包含前导双引号时,Ruby不会解析CSV

当单元格/字段包含前导双引号时,Ruby不会解析CSV
EN

Stack Overflow用户
提问于 2016-02-07 23:59:43
回答 4查看 3.3K关注 0票数 4

当其中一列包含双引号“字符”时,我该如何解析CSV文件?我收到“第xxx行缺少或丢失引号”错误,因为其中有一个尾随的双引号。确切的错误是“第58行缺少或丢失引号(CSV::MalformedCSVError)”。数据来自解析另一个设备(防火墙)配置的应用程序,并且“已被管理员作为注释添加到此设备的配置中,因此超出了我的控制范围。”

示例输入数据(无法提供文件,它们本质上是敏感的):

代码语言:javascript
复制
"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“”。如果最后一列中只有一个双引号,那么到目前为止,我的脚本似乎工作得很好。

复制所需的最低代码:

代码语言:javascript
复制
#!/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)

理想情况下,正常工作的代码将忽略额外的引号或替换它或任何其他潜在的有问题的字符。可能值得注意的是,考虑到最初的防火墙配置是由一个人配置的,该人可以将额外的引号放在几乎任何单元格/字段中。

EN

回答 4

Stack Overflow用户

发布于 2016-02-08 00:17:09

这里有一个技巧可能会有所帮助。使用:quote_char => "'" (假设CSV中的列中的值没有单引号字符),这将在读取的值中包含双引号-您可以通过代码删除双引号:

示例:

代码语言:javascript
复制
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类。

代码语言:javascript
复制
File.open("/path/to/file") do |f|
  f.each_line do |for|
    columns = row.split(",")
  end
end
票数 4
EN

Stack Overflow用户

发布于 2016-02-08 01:19:45

您可以从CSV::MalformedCSVError中解救出来,并为有此类问题的行创建单独的处理程序,但这意味着您必须单独解析每一行,并且您将丢失标题行中的列名。

代码语言:javascript
复制
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 ...这样的选择。

票数 3
EN

Stack Overflow用户

发布于 2016-02-08 23:25:22

Tin Man的想法被证明是最好的,基本上读取了所有的文件,更改了我不想要的部分。该脚本随后写入可由CSV类读取的已清理文件。这允许我在需要的时候添加更多的替换。

我选择使用the Rio gem来完成工作。

代码的基本思想:

代码语言:javascript
复制
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“替换。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35255668

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档