【发布时间】:2019-11-22 16:00:09
【问题描述】:
我有一个类似How can I properly align UTF-8 strings with Perl's printf?的问题:
我的 (Linux) 系统的区域设置默认为 LC_CTYPE=de_DE.UTF-8,我编写了一个 Perl 程序(使用 perl-5.26.1),它“不”使用 Unicode 字符,但有些来自 ISO Latin-1 字符集(即° 例如)。
因此,我没有在我的 Perl 脚本中激活任何 Unicode 或区域设置功能。
“Everything”似乎在一个例外情况下工作正常:我使用%-10s 的printf 格式来对齐字符串,但这不能按预期工作。
在调试器中播放我发现了这种行为:
DB<1> $s='X°X'
DB<2> printf("_%3s_\n", $s)
_X°X_
目前看起来还不错...
DB<3> printf("_%4s_\n", $s)
_X°X_
哎呀;不应该是"_ X°X_"吗?
DB<4> printf("_%5s_\n", $s)
_ X°X_
减一?
DB<5> x length($s)
0 4
不应该是3吗?
DB<8> x ord($s[1])
0 0
DB<9> x $s
0 'X°X'
DB<10>
° 不应该被编码为一个字节吗?我认为 UTF-8 将未修改的 Latin-1 范围映射到 Unicode。
所以问题可能是:
发生了什么事?
这是 Perl 错误吗?
如果不是,如何修复格式和字符串长度?
【问题讨论】:
-
@Keith Thompson:我之前读过,但实际上en.wikipedia.org/wiki/UTF-8#Codepage_layout 暗示这不是真的:拉丁语 1 的 部分 被逐字映射为 UTF-8。特别是“U+00B0°度符号”。
-
维基百科页面指出 $B0 在 utf-8 编码方案的连续字节范围内,由此可知 Unicode 代码点 U+00B0 未按 1:1 映射。分析 utf8 编码的规范表明,如果设置了 utf8 代码的第一个八位字节的第 7 位,则该字节包含指示代码长度的位,因此该范围内的任何代码点都不可能进行 1:1 映射U+0080 到 U+00FF。
-
@collapsar:好的,请原谅我对 UTF-8 编码的误解。
-
所以
°的Unicode字符码还是$B0,但实际编码是$C2 $B0? -
@U.Windl:Unicode 对字符 0..255 使用相同的数值。 UTF-8 将 0..127 (ASCII) 范围内的每个字符编码为一个字节,并将 128..255 范围内的每个字符(ASCII 之外,Latin-1 之内)编码为两个字节。最多 2047 个字符也是编码为两个字节。请记住,UTF-8 不是 Unicode;它是 Unicode 的几种编码之一。
标签: perl utf-8 character-encoding printf