首页 > 解决方案 > Ruby 编码替换错误

问题描述

我正在尝试读取一个文本文件,其中包含许多带有重音符号(标点符号)的字符串,并使用 Ruby(不是 On Rails)用那些没有这些重音符号的字符串填充数据库。

例如我有:

J'ai été mise au courant des éventualités à temps。

我想将整行替换为以下字符串:

J'ai ete mise au courant des eventualites a temps。

因此,为此我找到了应该有效的方法:

    def convert_to_ascii(s)
        undefined = ''
        fallback = { 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A',
                   'Å'=>'A', 'Æ'=>'AE', 'Ç'=>'C', 'È'=>'E', 'É'=>'E',
                   'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I',
                   'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O',
                   'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U',
                   'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'à'=>'a', 'á'=>'a',
                   'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'ae',
                   'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e',
                   'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ñ'=>'n',
                   'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o',
                   'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ü'=>'u',
                   'ý'=>'y', 'ÿ'=>'y' }

        s.encode('ASCII',fallback: lambda { |c| fallback.key?(c) ? fallback[c] : undefined })
   end

但它只是给了我以下字符串:

J'ai t mise au courant des ventualits temps。

甚至:

J'ai t' mise au courant des 'ventualit's temps。

我不明白为什么它不起作用...

编辑:

我正在使用

file = File.open(i_FileName, 'r:utf-8')

要读取文件,我将其替换为

file = File.open(i_FileName, 'r:iso-8859-1:utf-8')

它就像一个魅力!

标签: rubystringasciiencode

解决方案


TL;DR:使用String#unicode_normalize.

可能是 1 个符号(所谓的 Unicode 组合形式)以及 2(两个)不同的符号(Unicode 分解形式)引发了意想不到的结果。

"J'ai été mise au courant des éventualités à temps.".
  unicode_normalize(:nfd).
  gsub(/./) { |m| m.ord > 255 ? '' : m }
#⇒ "J'ai ete mise au courant des eventualites a temps."

或者,甚至更简单:

"J'ai été mise au courant des éventualités à temps.".
  unicode_normalize(:nfd).gsub(/[\u0300-\u036F]/, '')
#⇒ "J'ai ete mise au courant des eventualites a temps."

我们在这里所做的是:我们将字符串规范化为分解形式(所有组合的变音符号成为单独的符号。)然后我们用String#gsub.


如果您觉得丢掉现有代码感到遗憾,请将字符串规范化为组合形式并使用您的encode,现在它可以工作了。

composed = "J'ai été mise au courant des éventualités à temps.".
   unicode_normalize(:nfc) # NOTE :nfc parameter

composed.encode(.....)

推荐阅读