在Ruby中确定文件的编码

Gra*_*son 7 ruby io file internationalization

我想出了一种方法来确定我传入的文件的编码(或至少猜测它):

def encoding_type(file_path)
 File.read(file_path).encoding.name
end
Run Code Online (Sandbox Code Playgroud)

这个问题是我有一个15GB的文件,这意味着整个文件被读入内存.

反正有没有完成我在这个方法中做的事情而不需要将整个文件读入内存?

Dar*_*cks 7

file -mime命令将返回文件的 MIME 类型和编码:

file -mime myfile

myfile: text/plain; charset=iso-8859-1

def detect_charset(file_path)
  `file --mime #{file_path}`.strip.split('charset=').last
rescue => e 
  Rails.logger.warn "Unable to determine charset of #{file_path}"
  Rails.logger.warn "Error: #{e.message}"
end
Run Code Online (Sandbox Code Playgroud)


jro*_*ind 5

您在问题中建议的方法不会按照您的想法进行。它只会将文件设置为Encoding.default_internal编码,可能在从Encoding.default_external. 这些通常都是UTF-8。编码将始终Encoding.default_internal在您运行该代码之后,而不是从实际文件中猜测或确定编码。

如果您有一个文件并且您真的不知道它是什么编码,那么您确实必须猜测。没有办法 100% 确定您已经按照作者的意图得到了正确的结果(并且某些文件已损坏和混合编码或在任何编码中都不合法)。

有一些带有启发式方法的库旨在尝试和猜测(它们不会一直都是正确的)。

这是我自己从未真正使用过的一个,但我在 10 分钟的谷歌搜索中发现了一个可能的前景:https : //github.com/oleander/rchardet 可能还有其他的 ruby​​ gem 用于此。您也可以使用 ruby​​ system() 来调用尝试执行此操作的 linux 命令行实用程序,上面有人提到了 Linuxfile命令。

如果你不想加载整个文件来测试它,你当然可以只加载它的一部分。也许 chardet 库的工作越可靠,它得到的越多,但是,当然,只需读取前 X 个字节文件,然后让 chardet 猜测它的编码。

 require 'chardet19'

 first1000bytes = File.read(file, 1000)
 cd = CharDet.detect(first1000bytes)
 cd.encoding
 cd.confidence
Run Code Online (Sandbox Code Playgroud)

您还可以随时检查 ruby​​ 中的任何字符串是否对其设置的编码有效:

 str.valid_encoding?
Run Code Online (Sandbox Code Playgroud)

所以你可以简单地通过各种编码,看看它是否有效:

 orig_encoding = str.encoding

 str.force_encoding("ISO-8859-1").valid_encoding?
 str.force_encoding("UTF-8").valid_encoding?

 str.force_enocding(orig_encoding) # put it back to what it was
Run Code Online (Sandbox Code Playgroud)

但是,一个文件肯定有可能在多个编码中有效,或者在给定的编码中有效,但在该编码中被人类解读为无意义。

如果你有你最好的猜测编码,但它仍然不是valid_encoding?那种编码,它可能只有几个坏字节。您可以在 ruby​​ 2.1 中使用String.scrub删除它们,或者在其他 ruby​​ 版本中使用 String.scrub 的这个纯红宝石反向移植

希望这有助于让您了解您正在处理的内容以及您的选择。