在下面的:my $string = "Can you \x{FB01}nd my r\x{E9}sum\x{E9}?\n";
x{FB01}
和 x{E9}
是代码点。并且代码点通过编码方案编码为一系列八位字节。
所以字符è
其中有代码点 \x{FB01}
是 $string
字符串的一部分.但这是如何工作的?是 所有字符在这句话中(包括 ASCII 的)通过 UTF-8
编码?
如果是,为什么会出现以下行为?
my $str = "Some arbitrary string\n";
if(Encode::is_utf8($str)) {
print "YES str IS UTF8!\n";
}
else {
print "NO str IT IS NOT UTF8\n";
}
这打印
"NO str IT IS NOT UTF8\n"
另外 Encode::is_utf8($string)
返回 true
.$string
以何种方式和 $str
不同,一个被认为是 UTF-8
而另一个不是?无论如何,
$str
的编码是什么? ? ASCII 码?这是 Perl
的默认设置吗? ?
最佳答案
在 C 中,字符串是八位字节的集合,但 Perl 有两种字符串存储格式:
因此,您不需要编码代码点以将它们存储在字符串中。
my $s = "\x{2660}\x{2661}";
say length $s; # 2
say sprintf '%X', ord substr($s, 0, 1); # 2660
say sprintf '%X', ord substr($s, 1, 1); # 2661
(在内部,称为“utf8”的 UTF-8 扩展用于存储 72 位字符的字符串。除了意识到性能影响外,您不需要知道这些,但存在暴露这一事实的错误。 )
编码器
is_utf8
报告标量包含哪种类型的字符串。这是一个除了调试我之前提到的错误之外完全没有用的功能。"abc"
的值(或 OP 中的字符串 $str
),因此 Perl 使用了更高效的 8 位 (UTF8=0) 字符串格式。 "\x{2660}\x{2661}"
的值(或 OP 中的字符串 $string
),因此 Perl 使用 72 位(UTF8=1)字符串格式。 零是零,无论它存储在浮点数、有符号整数还是无符号整数中。类似地,字符串的存储格式不传达有关字符串值的信息。
实际上,Perl 会在两种格式之间随意切换。例如,如果您连接
$string
与 $str
,您将获得 72 位格式的字符串。您可以使用内置函数
utf8::downgrade
更改字符串的存储格式和 utf8::upgrade
,如果您需要解决错误。utf8::downgrade($s); # Switch to strings of 8-bit values (UTF8=0).
utf8::upgrade($s); # Switch to strings of 72-bit values (UTF8=1).
您可以使用 Devel::Peek 查看效果。
>perl -MDevel::Peek -e"$s=chr(0x80); utf8::downgrade($s); Dump($s);"
SV = PV(0x7b8a74) at 0x4a84c4
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x7bab9c "\200"\0
CUR = 1
LEN = 12
>perl -MDevel::Peek -e"$s=chr(0x80); utf8::upgrade($s); Dump($s);"
SV = PV(0x558a6c) at 0x1cc843c
REFCNT = 1
FLAGS = (POK,pPOK,UTF8)
PV = 0x55ab94 "\302\200"\0 [UTF8 "\x{80}"]
CUR = 2
LEN = 12
关于string - Perl 的默认字符串编码和表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17222685/