以下内容:
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
的默认值吗?
答案 0 :(得分:8)
在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
(在内部,UTF-8的扩展称为“utf8”用于存储72位字符串。除了意识到性能影响之外,这不是你应该知道的事情,但是有一些错误会暴露出来这个事实。)
编码is_utf8
报告标量包含的字符串类型。除了调试我之前提到的错误之外,它是一个绝对没用的功能。
"abc"
的值(或OP的$str
中的字符串),因此Perl使用更有效的8位(UTF8 = 0)字符串格式。 / LI>
"\x{2660}\x{2661}"
的值(或OP的$string
中的字符串),因此Perl使用72位(UTF8 = 1)字符串格式。 / LI>
零是零,无论它是存储在浮点数,有符号整数还是无符号整数中。类似地,字符串的存储格式不传达有关字符串值的信息。
事实上,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
答案 1 :(得分:5)
\ x {FB01}和\ x {E9}是代码点。
不安静,大括号内的数值是代码点。整个\ x表达式只是一个字符的表示法。字符有几种符号,大多数以反斜杠开头,但常见的是简单的字符串文字。你不妨写一下:
use utf8;
my $string = "Can you find my résumé?\n";
# ↑ ↑ ↑
代码点通过编码方案编码为一系列八位字节。
是的,但到目前为止,你的字符串是一串字符,而不是八位字节的缓冲区。
但这是如何运作的?
字符串由字符组成。这只是Perl的模型。作为程序员,你应该在这个级别处理它。
当然,计算机不能,而内部数据结构必须具有某种形式的内部编码。由于"Perl can't keep a secret",细节偶尔会泄漏,所以会产生太多的混淆。
这句话中的所有字符(包括ASCII字符)都是通过UTF-8编码的吗?
不,内部编码是松散的UTF8(没有破折号)。它没有UTF-8(a.k.a. UTF-8-strict)的一些限制。
编码:: is_utf8
...是一个内部函数,是clearly marked as such。你作为程序员不应该偷看。但既然你想要偷看,没有人可以阻止你。 Devel::Peek::Dump是进入内部的更好工具。
阅读http://p3rl.org/UNI,了解Perl中的编码主题。
答案 2 :(得分:3)
is_utf8
是一个命名不佳的函数,并不意味着您认为它意味着什么或者任何与之相关。您的问题的答案是$string
没有编码,因为它没有编码。当您使用某种编码调用Encode::encode
时,其结果将是一个已编码的字符串,并具有已知编码