Ruby中的字符串编码

7

我最近开始接触Ruby中的编码,但是有些行为让我感到困惑。

我使用的版本是2.2.3p173,显示如下:

__ENCODING__             #=> #<Encoding:UTF-8>  Default encoding in 2.2.3

"my_string".encoding     #=> #<Encoding:UTF-8>
Object.to_s.encoding     #=> #<Encoding:US-ASCII>
Object.new.to_s.encoding #=> #<Encoding:ASCII-8BIT>

这种编码不一致的情况是由什么原因引起的?
2个回答

6

不错的发现!

简短的答案是,这完全是任意的,取决于 Ruby 内部构建返回的字符串的方式。

有许多内部 C 函数构造空字符串或带有 US-ASCII 编码的字面字符串:rb_usascii_str_new 等。它们经常用于通过附加较小的字符串片段来构造字符串。几乎每个 to_s 方法都会这样做:

[].to_s.encoding
#<Encoding:US-ASCII>
{}.to_s.encoding
#<Encoding:US-ASCII>
$/.to_s.encoding
#<Encoding:US-ASCII>
1.to_s.encoding
#<Encoding:US-ASCII>
true.to_s.encoding
#<Encoding:US-ASCII>
Object.to_s.encoding
#<Encoding:US-ASCII>

那么为什么不使用 Object.new.to_s 呢?关键在于 Object#to_s 是每个类的回退 to_s 方法,因此为了使其通用又信息丰富,他们编写了代码来输出对象内部指针的值。最简单的方法是使用 sprintf%p 格式化符。然而,谁编写了 Ruby 的 sprintf 包装器 rb_sprintf,懒得设置编码,直接将编码设置为 NULL ,这将回退到 ASCII-8BIT 。因此,一般返回格式化字符串的任何内容都将具有此编码:

Object.new.to_s
#<Encoding:ASCII-8BIT>
nil.sort rescue $!.to_s.encoding
#<Encoding:ASCII-8BIT>
[].each.to_s.encoding
#<Encoding:ASCII-8BIT>

对于由脚本定义的字符串,它们将像您预期的那样获得默认编码UTF-8。


2
如果你尝试以下操作:

ObjectC中被定义。

String(123456).encoding #=> #<Encoding:ASCII-8BIT>
"123456".encoding       #=> #<Encoding:UTF-8>

我没有深入研究过 Ruby 源代码,但是它似乎在 to_s 中硬编码了编码(rb_usascii_str_new2)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接