在Ruby 1.9.X中等效的Iconv.conv(“UTF-8 // IGNORE”,…)?

我正在从远程源读取数据,偶尔会在另一个编码中获得一些字符。 它们并不重要。

我想获得一个“最佳猜测”utf-8字符串,并忽略无效数据。

主要目标是获取我可以使用的字符串,而不是遇到如下错误:

  • 编码:: UndefinedConversionError:从ASCII-8BIT到UTF-8的“\ xFF”:
  • utf-8中的字节序列无效

我以为是这样的:

string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")

用’?’取代所有的知识。

要忽略所有未知数, :replace => ''

string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "")

编辑:

我不确定这是否可靠。 我已进入偏执模式,并一直在使用:

string.encode("UTF-8", ...).force_encoding('UTF-8')

脚本似乎正在运行,现在好了。 但我很确定我早些时候会遇到错误。

编辑2:

即便如此,我仍然会出现间歇性的错误。 不是每一次,请注意。 只是有时候。

也可以使用String #charsString#each_char

 # Table 3-8. Use of U+FFFD in UTF-8 Conversion # http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf) str = "\x61"+"\xF1\x80\x80"+"\xE1\x80"+"\xC2" +"\x62"+"\x80"+"\x63"+"\x80"+"\xBF"+"\x64" p [ 'abcd' == str.chars.collect { |c| (c.valid_encoding?) ? c : '' }.join, 'abcd' == str.each_char.map { |c| (c.valid_encoding?) ? c : '' }.join ] 

从Ruby 2.1开始,可以使用String#scrub

 p [ 'abcd' == str.scrub(''), 'abcd' == str.scrub{ |c| '' } ] 

这对我很有用:

 "String".encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "").force_encoding('UTF-8') 

要忽略字符串中未正确UTF-8编码的所有未知部分,以下(如您最初发布的那样)几乎可以执行您想要的操作。

 string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "") 

需要注意的是,如果认为字符串已经是UTF-8,则编码不会执行任何操作。 因此,您需要更改编码,通过编码仍然可以编码UTF-8可以编码的全套unicode字符。 (如果你不这样做,你会破坏任何不在该编码中的字符 – 7位ASCII将是一个非常糟糕的选择!)所以请通过UTF-16:

 string.encode('UTF-16', :invalid => :replace, :replace => '').encode('UTF-8') 

在@masakielastic的帮助下,我使用#chars方法为个人目的解决了这个问题。

诀窍是将每个角色分解为自己独立的块, 以便ruby可以失败

Ruby在面对二进制代码等时需要失败。如果你不允许ruby继续前进并且在这个问题上遇到困难。 所以我使用String #chars方法将给定的字符串分解为一个字符数组。 然后我将该代码传递给一个清理方法,该方法允许代码在字符串中包含“微伪”(我的造币)。

因此,给定一个“脏”字符串,假设您在图片上使用了File#read #read。 (我的情况)

 dirty = File.open(filepath).read clean_chars = dirty.chars.select do |c| begin num_or_letter?(c) rescue ArgumentError next end end clean = clean_chars.join("") def num_or_letter?(char) if char =~ /[a-zA-Z0-9]/ true elsif char =~ Regexp.union(" ", ".", "?", "-", "+", "/", ",", "(", ")") true end end 

允许代码在过程中的某个地方失败似乎是通过它的最佳方式。 只要您在块中包含这些失败,您就可以获取仅接受UTF-8接受的ruby部分的可读内容

我对单行使用String#encode ala string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")没有好运。 不能为我可靠地工作。

但我写了一个纯粹的ruby“回填”String#scrub到MRI 1.9或2.0或任何其他不提供String#scrub的ruby。

https://github.com/jrochkind/scrub_rb

它使String#scrub在没有它的ruby中可用; 如果在MRI 2.1中加载,它将不执行任何操作,您仍将使用内置的String#scrub,因此它可以让您轻松编写可在任何这些平台上运行的代码。

它的实现有点类似于其他答案中提出的其他char-by-char解决方案,但它不使用流控制的exception(不要那样做),经过测试,并提供与MRI 2.1 String兼容的API #擦洗