Cha*_*eak 1 ruby encoding encode ruby-on-rails utf-8
在发布到StackOverflow之前我已尝试过所有内容 我真的希望有人可以提供帮助,但我非常绝望.
所以,我有一个服务,通过客户提供的XML提要将数据上传到我们的数据库.这些XML文件通常声称是UTF-8编码,但显然有很多无效的字节序列.我可以通过在导入之前运行以下Linux命令来清理这些文件并将它们完美地导入我们的数据库:
tr -cd '^[:print:]' < original.xml > clean.xml
Run Code Online (Sandbox Code Playgroud)
只需运行这一个Linux命令,我就可以使用Rails中的Nokogiri将所有数据导入我的数据库.
问题是我们正在Heroku上部署,我无法使用Linux命令预处理该文件.我花了最后一周在互联网上搜索基于Rails的本地解决方案来解决这个问题,但是没有一个能够解决问题.在我完成我尝试过的所有建议之前,这是我的原始代码:
data_source = ARGV[0]
data_file = open data_source
data_string = data_file.read
doc = Nokogiri::XML.parse(data_string)
doc.xpath(".//job").each do |node|
hash = node.element_children.each_with_object(Hash.new) do |e, h|
h[e.name.gsub(/ /,"_").strip.downcase.to_sym] = e.content
data.push(newrow)
end
end
Run Code Online (Sandbox Code Playgroud)
在原始文件上运行此操作会产生错误:"UTF-8中的无效字节序列"
以下是我尝试过的所有有用的建议,但都失败了.
使用编码器
Coder.clean!(data_string,"UTF-8")
强制编码
data_string.force_encoding('BINARY').encode('UTF-8',:undef =>:replace,:replace =>'')
转换为UTF-16并返回UTF-8
data_string.encode!('UTF-16','UTF-8',:invalid =>:replace,:replace =>'')data_string.encode!('UTF-8','UTF-16')
使用valid_encoding?
data_string.chars.select {|我| i.valid_encoding?}.加入
没有删除任何字符; 生成"无效字节序列"错误.
在打开文件时指定编码
我实际上编写了一个函数,它可以尝试每种编码,直到它可以无错误地打开文件并转换为UTF-8(@file_encodings是每个可能的文件编码的数组):
@file_encodings.each do |enc|
print "#{enc}..."
conv_str = "r:#{enc}:utf-8"
begin
data_file = File.open(fname, conv_str)
data_string = data_file.read
rescue
data_file = nil
data_string = ""
end
data_string = data_string.encode(enc, :invalid => :replace, :undef => :replace, :replace => "")
unless data_string.blank? print "\n#{enc} detected!\n"
return data_string
end
Run Code Online (Sandbox Code Playgroud)
使用Regexp删除非printables:
data_string.gsub!(/ [^ [:print:]] /,"")data_string.gsub!(/ [[:cntrl:] && [^ \n\r]] /,"")
(我还试图变体包括/ [!^ A-ZA-Z0-9〜`@#$%^&*()-_ = + [{]}\|;:<>?"',/ \] /)
对于上述所有情况,结果都是相同的......要么发生"无效字节序列"错误,要么在仅读取4400行后中途切断文件.
那么,为什么Linux"tr"命令可以正常工作,而这些建议中的任何一个都无法在Rails中完成.
我最终做的是非常不优雅,但完成工作.我检查了停止Nokogiri(row.last)的每一行,并寻找奇怪的角色.每一个我发现我添加到一个字符类然后gsub!编辑出来,像这样(控制字符不会在这里打印,但你明白了):
data_string.gsub!(/[Crazy Control Characters]/,"")
Run Code Online (Sandbox Code Playgroud)
但是我的纯粹主义者坚持认为应该有更优雅,更通用的解决方案.
(我已经将我的所有代码缩进了四个空格,但编辑器似乎没有采用它.)
Ruby 2.1有一个名为String.scrub的新方法,这正是你需要的.
如果字符串是无效的字节序列,则用给定的替换字符替换无效字节,否则返回self.如果给出了块,则用块的返回值替换无效字节.
查看文档以获取更多信息.
http://ruby-doc.org/core-2.1.0/String.html#method-i-scrub