String 在Perl中,为什么utf-8字符串在拆分为字符时打印方式不同?
使用时,特殊构造的字符串的打印方式不同String 在Perl中,为什么utf-8字符串在拆分为字符时打印方式不同?,string,perl,unicode,utf-8,language-lawyer,String,Perl,Unicode,Utf 8,Language Lawyer,使用时,特殊构造的字符串的打印方式不同 print $b; 或 一个最简单的例子是: #!perl use warnings; use strict; use Encode; my $b = decode 'utf8', "\x{C3}\x{A1}\x{E2}\x{80}\x{93}\x{C3}\x{A1}"; # 'á–á' in Unicode; print $b, "\n"; print for split //, $b 控制台屏幕上的输出(我想我使用cp860)是: 或十六进制
print $b;
或
一个最简单的例子是:
#!perl
use warnings;
use strict;
use Encode;
my $b = decode 'utf8', "\x{C3}\x{A1}\x{E2}\x{80}\x{93}\x{C3}\x{A1}"; # 'á–á' in Unicode;
print $b, "\n";
print for split //, $b
控制台屏幕上的输出(我想我使用cp860)是:
或十六进制:
C3 A1 E2 80 93 C3 A1
E1 E2 80 93 E1
(当然由0D 0A
分隔,即\r\n
)
问题是为什么角色的呈现方式不同
令人惊讶的是,没有em破折号,效果就消失了。对于较长的字符串可以看到这种效果,如下例所示
对于字符串“Éles mi tío Toño–Antonio pérez”(在程序中键入为Unicode;注意这两行是不同的!):
然而,对于字符串“El es mi tío Toño,Antonio pérez”:
╔l es mi tÝo To±o, Antonio PÚrez
╔l es mi tÝo To±o, Antonio PÚrez
没有什么不好的事情发生,两条线以相同的方式渲染。唯一的区别是存在一个破折号–
,即'\x{E2}\x{80}\x{93}'
另外,打印联接“”,拆分/,$b
给出与打印$b相同的结果代码>但与拆分打印不同,$b代码>
如果我添加binmode标准输出'utf8'代码>,则两个输出都是├í
=E2 80 93 C3 A1
所以我的问题不是如何避免,而是为什么会发生这种情况:为什么同一个字符串在拆分时表现不同
显然,在这两种情况下,utf8
标志都处于启用状态。下面是一个更详细的程序,它显示了有关这两个字符串的更多信息:解码之前的$a
和解码之后的$b
:
#!perl
use warnings;
use strict;
use 5.010;
use Encode;
my $a = "\x{C3}\x{A1}\x{E2}\x{80}\x{93}\x{C3}\x{A1}"; # 'á–á' in Unicode;
my $b = decode 'utf8', $a;
say '------- length and utf8 ---------';
say "Length (a)=", length $a, ", is_uft8(a)=", (Encode::is_utf8 ($a) // 'no'), ".";
say "Length (b)=", length $b, ", is_uft8(b)=", (Encode::is_utf8 ($b) // 'no'), ".";
say '------- as a variable---------';
say "a: $a";
say "b: $b", ' <== *** WHY?! ***';
say '------- split ---------';
print "a: "; print for split //, $a; say '';
print "b: "; print for split //, $b; say ' <== *** DIFFERENT! ***';
say '------- split with spaces ---------';
print "a: "; print "[$_] " for split //, $a; say '';
print "b: "; print "[$_] " for split //, $b; say '';
say '------- split with properties ---------';
print "a: "; print "[$_ is_utf=" . Encode::is_utf8 ($_) . " length=" . length ($_) . "] " for split //, $a; say '';
print "b: "; print "[$_ is_utf=" . Encode::is_utf8 ($_) . " length=" . length ($_) . "] " for split //, $b; say '';
say '------- ord() ---------';
print "a: "; print ord, " " for split //, $a; say '';
print "b: "; print ord, " " for split //, $b; say '';
#!perl
使用警告;
严格使用;
使用5.010;
使用编码;
my$a=“\x{C3}\x{A1}\x{E2}\x{80}\x{93}\x{C3}\x{A1}”;#Unicode中的á–á;
my$b=解码'utf8',$a;
说出'----长度和utf8---';
说“长度(a)=”,长度$a,”,is_uft8(a)=”,(编码::is_utf8($a)/“否”),“;
说“长度(b)=”,长度$b,”,is_uft8(b)=”,(编码::is_utf8($b)/‘否’),“;
把“-----作为变量----------”;
说“a:$a”;
说“b:$b”,区别在于所打印的字符串是否包含任何大于255的字符<代码>打印
只知道在那种情况下你做错了什么[1]
给定一个没有:encoding
的句柄,print
需要一个字节字符串(字符串≤255)
当它不接收字节(字符串包含大于255个字符)时,它会通知您错误(“宽字符”),并猜测您打算使用UTF-8对字符串进行编码
您可以将不带的手柄上的打印:编码视为执行以下操作:
if ($s =~ /[^\x00-\xFF]/) {
warn("Wide character");
utf8::encode($s);
}
与
my $b = "\xE1\x{2013}\xE1";
因此,你正在做什么
print "\xE1\x{2013}\xE1";
print "\xE1";
print "\x{2013}";
print "\xE1";
Perl注意到您忘记编码,警告您,并打印使用UTF-8编码的字符串
Perl无法知道您忘记了编码,所以它会打印您要求它打印的内容
Perl注意到您忘记编码,警告您,并打印使用UTF-8编码的字符串
脚注
存储格式的选择(由返回的是_utf8
)不应产生任何影响<代码>打印
正确地不受其影响
utf8::downgrade( my $d = chr(0xE1) ); print($d); # UTF8=0 prints E1
utf8::upgrade( my $u = chr(0xE1) ); print($u); # UTF8=1 prints E1
请避免使用my$a
和my$b
。它可以搞乱排序和一些常用的库sub。是的,对!我使用它们只是为了便于阅读:-)在真实的程序中不能使用。啊哈,现在我明白了!非常简单:print
将整个字符串解释为utf8
,如果该字符串至少包含一个ASCII范围以上的字符。当我拆分字符串时,print
仅将ASCII范围以上的单个字符(1个字符的字符串)解释为utf8,而将其他字符解释为ASCII。print
将整个字符串解释为需要编码的Unicode码点,前提是该字符串至少包含255以上的一个字符。(UTF-8是它的结尾,而不是它的开头。ASCII编码只有128个字符,而且print
并不像提到ASCII那样假定字符是文本。)在我理解你的意思之前,我读了几百遍。默认情况下,perl不会打印出任何大于255的代码点,因此它会将整个字符串转换回字节(代码点Re“默认情况下,perl不会打印出任何大于255的代码点”,正确。它不能。文件只能包含字节。除字节外的任何内容都需要转换为字节。:编码告诉perl如何执行此操作。Re“我认为按原样打印代码点是有意义的。”这没有意义。0x2660不能放在文件中。
if ($s =~ /[^\x00-\xFF]/) {
warn("Wide character");
utf8::encode($s);
}
my $b = decode 'utf8', "\x{C3}\x{A1}\x{E2}\x{80}\x{93}\x{C3}\x{A1}";
my $b = "\xE1\x{2013}\xE1";
print "\xE1\x{2013}\xE1";
print "\xE1";
print "\x{2013}";
print "\xE1";
print "\xE1\x{2013}\xE1"; # Wide char! C3 A1 E2 80 93 C3 A1
print "\xE1"; # E1
print "\x{2013}"; # Wide char! E2 80 93
utf8::downgrade( my $d = chr(0xE1) ); print($d); # UTF8=0 prints E1
utf8::upgrade( my $u = chr(0xE1) ); print($u); # UTF8=1 prints E1