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

时间:2011-10-24 01:46:58

标签: ruby encoding utf-8 iconv

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

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

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

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

6 个答案:

答案 0 :(得分:15)

我以为是这样的:

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:

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

答案 1 :(得分:3)

也可以使用

String #chars String#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| '' }
]

答案 2 :(得分:2)

这对我很有用:

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

答案 3 :(得分:2)

要忽略字符串中未正确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')

答案 4 :(得分:0)

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

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

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

因此,给定一个“脏”字符串,假设您在图片上使用了File#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部分的可读性

答案 5 :(得分:0)

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

但是我写了一个纯粹的红宝石“回填”String#scrub到MRI 1.9或2.0或任何其他没有提供String#scrub的红宝石。

https://github.com/jrochkind/scrub_rb

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

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