【问题标题】:Equivalent of Iconv.conv("UTF-8//IGNORE",...) in Ruby 1.9.X?相当于 Ruby 1.9.X 中的 Iconv.conv("UTF-8//IGNORE",...)?
【发布时间】:2011-10-24 01:46:58
【问题描述】:

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

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

主要目标是获得一个我可以使用的字符串,并且不会遇到以下错误:

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

【问题讨论】:

  • 您发布了一个答案并将其删除。这个答案看起来很有用。你能告诉我们为什么它不正确/有用吗?
  • 取消删除和评论。

标签: ruby encoding utf-8 iconv


【解决方案1】:

我以为是这样的:

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:

即便如此,我仍然会遇到间歇性错误。不是每次,请注意。只是偶尔。

【讨论】:

  • 你有没有想过这个问题?我正在尝试确定 iconv 是否可以在 1.9.3 中安全地替换为 String#encode(因为它会警告您弃用),但如果是这种情况,我无法从您的评论中判断。
  • 新手注意:编辑中的省略号指的是重复代码-整行是:string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "").force_encoding('UTF-8')
  • 您需要先通过 force_encoding 将字符串设置为正确的编码。 (注意:这不做任何编码,它只是设置表示)如果它是一个 html 文档,页面编码通常可以在元标记中找到。然后使用 encode 和 replace invalid/undef 来获取 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
]

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

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

【讨论】:

  • 如果你真的需要从 Ruby 2.0 开始的 iconv,考虑iconv gem
  • 感谢@masakielastic,iconv gem 解决了这个问题。
  • 我们对从 word 中粘贴的内容有很多问题,根据上面的答案,这有很大帮助:def find_invalid_chars(s) s.chars.select {|c| !c.valid_encoding? } 结束
【解决方案3】:

这对我很有用:

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

【讨论】:

    【解决方案4】:

    要忽略未正确 UTF-8 编码的字符串的所有未知部分(如您最初发布的那样),几乎可以满足您的要求。

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

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

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

    【讨论】:

      【解决方案5】:

      在@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
      

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

      【讨论】:

        【解决方案6】:

        我对 String#encode ala string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?") 的单行使用并不满意。不要为我可靠地工作。

        但我为 MRI 1.9 或 2.0 或任何其他不提供 String#scrub 的 ruby​​ 编写了 String#scrub 的纯红宝石“回填”。

        https://github.com/jrochkind/scrub_rb

        它使 String#scrub 在没有它的红宝石中可用;如果在 MRI 2.1 中加载,它将什么也不做,您仍将使用内置的 String#scrub,因此它可以让您轻松编写适用于任何这些平台的代码。

        它的实现有点类似于其他答案中提出的其他一些逐字符的解决方案,但它不使用流控制异常(不要这样做),经过测试并提供与MRI 2.1 字符串#scrub

        【讨论】:

          猜你喜欢
          • 2011-02-28
          • 2011-07-25
          • 1970-01-01
          • 2021-12-04
          • 2012-03-09
          • 1970-01-01
          • 1970-01-01
          • 2011-08-23
          相关资源
          最近更新 更多