这是一个很好的问题。为了调查,我们可以使用
Devel::Peek来深入了解存储在我们的字符串(或其他变量)中的实际内容。
首先,让我们从ASCII字符串开始。
$ perl -MDevel::Peek -E 'Dump "string"'
SV = PV(0x9688158) at 0x969ac30
REFCNT = 1
FLAGS = (POK,READONLY,pPOK)
PV = 0x969ea20 "string"\0
CUR = 6
LEN = 12
然后我们可以打开Unicode IO层并执行相同的操作。
$ perl -MDevel::Peek -CSAD -E 'Dump "string"'
SV = PV(0x9eea178) at 0x9efcce0
REFCNT = 1
FLAGS = (POK,READONLY,pPOK)
PV = 0x9f0faf8 "string"\0
CUR = 6
LEN = 12
接下来,让我们尝试手动添加一些宽字符
$ perl -MDevel::Peek -CSAD -e 'Dump "string \x{2665}"'
SV = PV(0x9be1148) at 0x9bf3c08
REFCNT = 1
FLAGS = (POK,READONLY,pPOK,UTF8)
PV = 0x9bf7178 "string \342\231\245"\0 [UTF8 "string \x{2665}"]
CUR = 10
LEN = 12
从这个例子中,你可以清楚地看到 Perl 已经正确地解释了 utf8。问题在于,如果我不使用 \x{}
转义序列来指定八进制值,那么它的表示就更像是一个普通的字符串。
$ perl -MDevel::Peek -CSAD -E 'Dump "string ♥"'
SV = PV(0x9143058) at 0x9155cd0
REFCNT = 1
FLAGS = (POK,READONLY,pPOK)
PV = 0x9168af8 "string \342\231\245"\0
CUR = 10
LEN = 12
所有Perl看到的都是字节,无法知道你将它们视为Unicode字符,与上面输入转义八进制数不同。现在让我们使用
decode
并看看会发生什么。
$ perl -MDevel::Peek -CSAD -MEncode=decode -E 'Dump decode "utf8", "string ♥"'
SV = PV(0x8681100) at 0x8683068
REFCNT = 1
FLAGS = (TEMP,POK,pPOK,UTF8)
PV = 0x869dbf0 "string \342\231\245"\0 [UTF8 "string \x{2665}"]
CUR = 10
LEN = 12
现在你可以看到,字符串的内部表示与使用
\x{}
转义时输入的内容匹配,这是正确的。实际上,它是从字节解码为字符,但当您看到 Peek 输出时,我认为更有意义。最后,您可以使用
utf8
pragma 来使 Perl 将源代码视为 utf8。
$ perl -MDevel::Peek -CSAD -Mutf8 -E 'Dump "string ♥"'
SV = PV(0x8781170) at 0x8793d00
REFCNT = 1
FLAGS = (POK,READONLY,pPOK,UTF8)
PV = 0x87973b8 "string \342\231\245"\0 [UTF8 "string \x{2665}"]
CUR = 10
LEN = 12
perldoc perlguts
会提供一些信息。请注意,字符串通常并不是神奇的;有时候只是看起来像而已。 - Jonathan Leffler