为什么 Ruby Integer 方法 'chr' 默认使用 ASCII-8 位,而不是 UTF-8?

Why does Ruby Integer method 'chr' use ASCII-8bit, not UTF-8 by default?

提问人:LancerRevolutionX 提问时间:2/6/2021 更新时间:2/6/2021 访问量:190

问:

根据它的源代码 https://www.rubydoc.info/stdlib/core/Integer:chr,如果没有提供参数,此方法使用 ASCII 编码,实际上,当使用参数和不参数调用时,它会给出不同的结果:

irb(main):002:0* 255.chr
=> "\xFF"

irb(main):003:0' 255.chr 'utf-8'
=> "ÿ"

为什么会这样?Ruby 不是应该在任何地方默认使用 UTF-8 吗?至少所有字符串似乎都用 UTF-8 编码:

irb(main):005:0> "".encoding
=> #<Encoding:UTF-8>
Ruby UTF-8 字符编码 ASCII

评论


答:

1赞 Jörg W Mittag 2/6/2021 #1

为什么会这样?

对于从 U+0000 到 U+007F (127) 的字符,绝大多数单八位字节和可变长度字符编码都同意编码。特别是,他们都同意是 ASCII 的严格超集。

换言之:对于包括 U+007F、ASCII 在内的字符,整个 ISO8859 系列、整个 DOS 代码页系列、整个 Windows 系列以及 UTF-8 实际上是相同的。因此,对于 U+0000 和 U+007F 之间的字符,ASCII 是合乎逻辑的选择:

0.chr.encoding
#=> #<Encoding:US-ASCII>

127.chr.encoding
#=> #<Encoding:US-ASCII>

但是,对于高于 127 的任何内容,或多或少没有两个字符编码一致。事实上,127 以上的绝大多数字符甚至不存在于绝大多数字符集中,因此在绝大多数字符编码中没有编码

换句话说:几乎不可能为 127 以上的字符找到单一的默认编码。

因此,Ruby 选择的编码是 ,它基本上是一种伪编码,意思是“这实际上不是文本,这是非结构化的未知二进制数据”。(对于歇斯底里的葡萄干,这种编码也别名为 ,我觉得这绝对可怕,因为 ASCII 是 7 位,句点,任何使用第 8 位的东西根据定义都不是 ASCII。Encoding::BINARYASCII-8BIT

128.chr.encoding
#=> #<Encoding:ASCII-8BIT>

255.chr.encoding
#=> #<Encoding:ASCII-8BIT>

另请注意,Integer#chr 仅限于单个八位字节,即范围为 0 到 255,因此这里实际上不需要多八位字节或可变长度编码。

Ruby 不是应该在任何地方默认使用 UTF-8 吗?

你说的是哪种编码?Ruby 大约有六个。

对于绝大多数编码,您的陈述是不正确的。

  • 区域设置编码是环境的默认编码
  • 文件系统编码是用于文件路径的编码:该值由文件系统确定
  • 对象的外部编码假定读取的文本和写入的文本的编码:默认值为区域设置编码IO
  • 对象的内部编码写入对象的 S 必须采用的编码,从对象读取的 S 必须转码为:默认值为默认内部编码,其默认值为 ,表示不会发生转码IOStringIOStringIOnil
  • 脚本编码是读取 Ruby 脚本的编码,脚本中的文字也将继承这种编码:它在脚本的开头设置了一个魔术注释,默认值为 UTF-8String

所以,正如你所看到的,有许多不同的编码,许多不同的默认值,其中只有一个是 UTF-8。这些编码实际上都与您的问题无关,因为既不是文字也不是对象。它是由该方法使用它认为合适的任何编码创建的对象。128.chrStringIOStringInteger#chr

评论

0赞 LancerRevolutionX 2/6/2021
另请注意,Integer#chr 仅限于单个八位字节,即范围为 0 到 255,因此这里实际上不需要多八位字节或可变长度编码。事实上,chr 方法可以处理多字节字符,但前提是您指定了正确的编码,例如:irb(main):002:0> 1050.chr 'utf-8' => "К"
0赞 Cary Swoveland 2/6/2021
你提到的“歇斯底里的葡萄干”让我想起了 1980 年代中期的一些著名电视广告。¯\_(ツ)_/¯