tl;dr汇总:给定一个以未知编码方式表示字符串的字节流,我应该尝试按什么顺序解释这些字节,以获得找到“正确”编码的最佳机会?
这个问题的例子
我有一个文件arrows.txt,我碰巧知道它是用⇈的单字符内容使用UTF-8保存的。如果我假装不知道该文件的编码是什么,Windows上的以下Ruby代码就会失败:
s = IO.read('foo.txt')
p s.encoding, #=> #<Encoding:IBM437>
s.valid_encoding?, #=> true
s.chars.to_a #=> ["\xE2", "\x87", "\x88"]它‘失败’,因为它告诉我,文件实际上有内容Γçê,并且一切都很好(编码是有效的)。
真实世界情景
我有Nginx日志文件和Akamai日志文件,它们对它们记录的查询没有任何特定的编码,我需要将这些数据作为UTF-8处理并存储在数据库中。大多数情况下,将每一行解释为UTF-8会产生一个具有有效编码的字符串,但有时不会。
我想要求Ruby为每一行尝试各种编码,以找到一个有效且可能(当然不是保证)正确的编码。
失败尝试
我最初编写了以下代码:
def guess_encoding( str, result='utf-8', *encodings )
# Try every encoding if none were passed in
encodings = Encoding.list if encodings.empty?
# Keep forcing a new encoding until we find one that is valid
unless encodings.find{ |e| str.force_encoding(e) && str.valid_encoding? }
raise "None of the supplied encodings was valid"
end
# Convert from the valid encoding to the desired, replacing 'bad' characters
str.encode(result, invalid: :replace, undef: :replace)
end这方面的问题是,Encoding.list中的第一个编码是ASCII-8BIT,它对所有字节流都有效。因此,如果我使用上面的代码并调用s2 = guess_encoding(s),结果是上面的三字节双箭头字符的字符串���。
最后,这个问题
我应该测试编码的顺序是什么,以提供最大的机会让第一个valid_encoding?成为正确的编码?对于使用的字节,哪种编码是最挑剔的,比如我应该先尝试它们,哪些公共编码是完全允许的,所以我应该最后尝试它们?
在猜测正确性时还有什么其他的试探方法吗?(如果一个特定的编码比另一个编码的字符少,那么它更有可能是正确的吗?)
发布于 2012-02-13 19:11:52
您可以尝试rchardet19宝石。它“在未知字符编码中获取一个字节序列,并尝试确定编码。”它还为它返回的编码提供了一个信任评分。在过去,它对我起了好几次作用,看起来它能完成你想要完成的任务。
示例用法:
require 'rchardet19'
cd = CharDet.detect("some data")
# => #<struct #<Class:0x102216198> encoding="ascii", confidence=1.0>发布于 2012-02-13 18:53:23
如果您的代码可以在unix/linux机器上运行,那么丝状 gem可能会很适合您。
gem install ruby-filemagic它是确定整个文件编码的最有用的工具,然后可以用于文件中的所有行。以下内容将帮助您开始使用它:
$ irb
irb(main):001:0> require 'filemagic'
=> true
irb(main):002:0> fm = FileMagic.new
=> #<FileMagic:0x7fd4afb0>
irb(main):003:0> fm.file('afile.zip')
=> "Zip archive data, at least v2.0 to extract"
irb(main):004:0>发布于 2012-02-13 18:53:51
当我处理写蜘蛛的时候,我总是从ISO-8859-1开始,然后是Win-1252。两者之间的差别很小,所以在大多数情况下都应该是合适的。我的第一个理由是,我认为你最有可能遇到他们。
如果有些东西不符合这些要求,那么我就用iconv把它转换成UTF-8,或者去掉对话口音,这样它在视觉上就像我们期望看到的一样,然后继续。
有些时候,没有什么是成功的;我有一些代码,它提取了偶像的所有编码,然后删除了所有的ASCII值,并试图为剩下的字符找到具有最高命中次数的编码。XML和HTML有时会出现格式错误,以致于没有任何帮助,当我恢复到消除口音的时候。
https://stackoverflow.com/questions/9265605
复制相似问题