ruby - 猜测日志文件中字节流的字符串编码

标签 ruby encoding

tl;dr summary:给定一个表示未知编码字符串的字节流,我应该尝试用什么编码以及以什么顺序解释这些字节以获得找到 '正确的'编码?

问题示例

我有一个文件 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? 成为正确的编码?哪些常见编码对使用的字节最挑剔,因此我应该首先尝试它们,哪些常见编码是完全宽松的,因此我应该最后尝试它们?

在猜测正确性时,我应该使用任何其他启发式方法吗? (如果特定编码产生的字符数少于另一种编码,是否更有可能是正确的?)

最佳答案

你可以试试 rchardet19 gem 。它“采用未知字符编码的字节序列,并尝试确定编码。”它还为您返回的编码提供置信度分数。它在过去曾多次为我工作,看起来它完成了您想要完成的事情。

示例用法:

require 'rchardet19'
cd = CharDet.detect("some data")
# => #<struct #<Class:0x102216198> encoding="ascii", confidence=1.0>

关于ruby - 猜测日志文件中字节流的字符串编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9265605/

相关文章:

php - 使用加密、代理 key 等混淆 GET id 变量

php - 是否可以在同一页面显示不同编码的数据?

ruby - 你如何在 ruby​​ 中编写二进制文字?

ruby-on-rails - Rails_admin, Date 添加更多接受格式

ruby-on-rails - 通过带作用域的关联保存时丢失属性 (Rails 4.0.0)

ruby-on-rails - ruby rails : "find_create_by_user"

ruby - 用 7n +1 填充 ruby​​ 中的数组

ruby - ActionMailer 字符串编码

java - HDFS文件编码转换器

encoding - 是否存在可发音的编码?