我可以在 Ruby 1.9 上设置默认字符串编码吗?

Posted

技术标签:

【中文标题】我可以在 Ruby 1.9 上设置默认字符串编码吗?【英文标题】:Can I set the default string encoding on Ruby 1.9? 【发布时间】:2011-01-06 22:06:25 【问题描述】:

这听起来可能微不足道,但它让我发疯了。自从上周五在 Ruby 1.9 上将应用程序发布到生产环境以来,我遇到了很多与字符编码相关的小异常。几乎所有的都是一些变化:

Encoding::CompatibilityError: incompatible character encodings: ASCII-8BIT and UTF-8

我们有一个国际用户群,所以很多名字都包含变音符号等。如果我将模板修复为在很多地方使用 force_encoding,它会在 Flash 消息帮助程序中弹出。等等。

目前看来,我已经确定了我所知道的所有内容,方法是在一个地方修补 ActiveSupport 的字符串连接,然后在我的每个源文件的顶部设置 # encoding: utf-8。但是,从现在开始,为了避免字符串分配问题,我可能必须记住对我曾经做过的每个 Ruby 项目的每个文件都这样做,永远,这种感觉在我的胃​​里并不好。我阅读了有关 -Ku 开关的信息,但所有内容似乎都在警告它是为了向后兼容并且可能随时消失。

所以我对 1.9 经验的人的问题是:在我的每个文件中设置 #encoding 真的有必要真的吗?有没有一种合理的方法可以在全球范围内做到这一点?或者,更好的方法是为绕过内部/外部默认值的字符串的非文字值设置默认编码?

提前感谢您的任何建议。

【问题讨论】:

【参考方案1】:

不要将文件编码与字符串编码混淆

文件顶部的 #encoding 语句的目的是让 Ruby 在读取/解释您的代码时知道,并且您的编辑器知道在编辑/读取文件时如何处理任何非 ASCII 字符 -- 仅当文件中至少有一个非 ASCII 字符时才需要。例如它在您的配置/语言环境文件中是必需的。

要一次在所有文件中定义编码,您可以使用 magic_encodinggem,它可以将uft-8魔术注释插入到您应用中的所有ruby文件中。

您在运行时遇到的错误 Encoding::CompatibilityError 是当您在程序执行期间尝试连接具有不同编码的两个字符串时发生的错误,并且它们的编码不兼容。

这很可能发生在:

您正在使用 L10N 字符串(例如 UTF-8),并将它们连接到例如ASCII 字符串(在你看来)

用户键入外语字符串(例如 UTF-8),您的视图尝试在某个视图中将其打印出来,以及您预定义的一些固定字符串(ASCII)。 force_encoding 将在此提供帮助。 Rails 1.9 中还有 Encoding::primary_encoding 为新字符串设置默认编码。 并且在Rails的config/application.rb文件中有config.encoding

来自您的数据库的字符串,然后与您视图中的其他字符串组合。 (它们的编码可能是任意一种,并且不兼容)。

旁注:确保在创建数据库时指定默认编码!

    create database yourproject  DEFAULT CHARACTER SET utf8;

如果您想在字符串中使用 EMOJI:

    create database yourproject DEFAULT CHARACTER SET utf8mb4 collate utf8mb4_bin;

所有可能包含 EMOJI 的字符串列的索引长度必须为 191 个字符。字符集 utf8mb4 整理 utf8mb4_bin

这是因为普通的 UTF8 最多使用 3 个字节,而 EMOJI 使用 4 个字节存储。

请查看这篇 Yehuda Katz 文章,该文章深入介绍了这一点,并且解释得很好: (特别是“不兼容的编码”部分)

http://yehudakatz.com/2010/05/05/ruby-1-9-encodings-a-primer-and-the-solution-for-rails/

http://yehudakatz.com/2010/05/17/encodings-unabridged/

和:

http://zargony.com/2009/07/24/ruby-1-9-and-file-encodings

http://graysoftinc.com/character-encodings

【讨论】:

我不想处理所有这些编码混乱,很高兴知道所有的边缘情况,但我希望那里没有边缘情况。只需将所有内容都视为 utf8,如果某些内容是其他内容,则必须这样声明。 @grosser:我同意 - 这是一个巨大的痛苦!更糟糕的是,因为它,他们搞砸了低级 IO 类,这些类曾经返回 8 位字节的字符串..现在他们返回解释的“谁知道是什么”字符串——如果你需要处理未解释的,那就太烦人了原始字节.. @grosser - 老实说。在 UTF8 存在之前,日本必须靠自己过日子。随着 Ruby 在日本的出现,以及 ISO-2022-JP 和 Shift_JIS 的存在,这就是它的未来。如果你想成为一个真正的纯粹主义者,还有一些字符也没有编码成 UTF-8。但总的来说,我绝对同意你的观点,我们都应该使用 UTF8 并完成它。【参考方案2】:

在你的config/application.rb添加

config.encoding = "utf-8"

config/environment.rb 中的Application.initialize! 行上方,添加以下两行:

Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8

希望这会有所帮助。

【讨论】:

看起来很有希望,但在例如加载 'xxx.rb',其中 xxx.rb 包含 utf8 config.encoding 用于 rails html 输出编码 afaik,与 ruby​​ 的字符串编码无关 这个答案也做出了假设(尽管公平)OP正在询问Rails。【参考方案3】:

http://zargony.com/2009/07/24/ruby-1-9-and-file-encodings

不要混淆文件编码和字符串编码!

【讨论】:

感谢 Trevoke;我知道区别。但是,字符串继承了创建它们的源文件的编码。 (除非它们来自另一个文件的 IO 操作;因此 default_internal 和 default_external 属性。)因此,虽然它们不一样,但它们之间有着深刻而令人沮丧的关联。我想要的是一种设置默认 string 编码而不必使用 #encoding 注释的方法。 你想知道的关于编码的一切:blog.grayproductions.net/categories/character_encodings 可能还有更多你希望永远不会学习的内容:)【参考方案4】:
String.module_eval "def initialize\nsuper\nputs encoding\nend"
=> nil
irb(main):006:0> String.new
ASCII-8BIT
=> ""

不确定如何在您的系统中实现您的字符串,但通过挂钩 String 对象的初始化方法,您可以为您在整个应用程序中创建的任何字符串设置编码。

【讨论】:

似乎无法修复使用 utf8 加载文件我试过: String.module_eval "def initialize\nsuper\nencoding = Encoding::UTF_8\nend" load 'xxx.rb' 在做了更多测试之后,我确实注意到很少调用字符串的初始化方法。但这只是一个建议,也许当您在应用程序中创建它们时调用所有字符串的方法?只需将编码行添加到其中而不是初始化。 (通过创建,我的意思是加载到内存中,解析,或者你有什么) 也许覆盖 require 可以解决问题,但我不愿意走这么远:D

以上是关于我可以在 Ruby 1.9 上设置默认字符串编码吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 os x 上使 ruby​​ 1.9 默认 [重复]

如何避免将魔术编码注释放在 Ruby 1.9 中每个 UTF-8 文件的顶部?

ruby 1.9 和 RSpec2 有啥好的突变测试工具吗?

ruby 1.9 中有没有办法从字符串中删除无效的字节序列?

Ruby 1.9:将字节数组转换为具有多字节 UTF-8 字符的字符串

Ruby:字符串在 1.9 中不再混入 Enumerable