在Perl中,为什么拆分为字符时utf-8字符串的打印方式不同?

亚历山大·盖布赫

使用时,特殊构造的字符串以不同的方式打印

print $b;

要么

print for split //, $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)是:

Wide character in print at xx.pl line 9.
├íÔÇô├í
Wide character in print at xx.pl line 10.
ßÔÇôß

或十六进制:

C3 A1 E2 80 93 C3 A1 
E1 E2 80 93 E1

0D 0A当然用分隔\r\n)。

问题是为什么角色呈现不同?

令人惊讶的是,效果消失了,但没有破折号。如下面的示例所示,对于较长的字符串,可以看到效果。

对于字符串“Éles mitíoToño–AntonioPérez”(在程序中键入Unicode;请注意,这两行是不同的!):

Wide character in print at xx.pl line 14.
├ël es mi t├¡o To├▒o ÔÇôAntonio P├®rez
Wide character in print at xx.pl line 15.
╔l 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}'

另外,print join '', split //, $b;给出的结果与相同,print $b;但有所不同print for split //, $b;

如果加binmode STDOUT, 'utf8';,则两个输出均为ÔÇô├í= E2 80 93 C3 A1。

所以我的问题不完全是关于如何避免它的问题,而是关于为什么发生这种情况的原因:为什么相同的字符串在拆分时的行为会有所不同?

显然,在两种情况下,该utf8标志都处于打开状态。这是一个更详细的程序,它显示有关两个字符串的更多信息:$abeforedecode$bafter decode

#!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 '';

这是它在控制台上的输出:

------- length and utf8 ---------
Length (a)=7, is_uft8(a)=.
Length (b)=3, is_uft8(b)=1.
------- as a variable---------
a: ├íÔÇô├í
Wide character in say at x.pl line 16.
b: ├íÔÇô├í <== *** WHY?! ***
------- split ---------
a: ├íÔÇô├í
Wide character in print at x.pl line 19.
b: ßÔÇôß <== *** DIFFERENT! ***
------- split with spaces ---------
a: [├] [í] [Ô] [Ç] [ô] [├] [í]
Wide character in print at x.pl line 22.
b: [ß] [ÔÇô] [ß]
------- split with properties ---------
a: [├ is_utf= length=1] [í is_utf= length=1] [Ô is_utf= length=1] [Ç is_utf= length=1] [ô is_utf= length=1] [├ is_utf= length=1] [í is_utf= length=1]
Wide character in print at x.pl line 25.
b: [ß is_utf=1 length=1] [ÔÇô is_utf=1 length=1] [ß is_utf=1 length=1]
------- ord() ---------
a: 195 161 226 128 147 195 161
b: 225 8211 225
池上

区别在于所打印的字符串是否包含任何大于255的字符。print只知道您在那种情况下做错了事[1]


给定一个no句柄:encodingprint需要一个字节字符串(字符串≤255)。

当它不接收字节(字符串包含> 255的字符)时,它会通知您错误(“宽字符”),并猜测您打算使用UTF-8对字符串进行编码。

您可以将printno:encoding当作一个句柄来做以下事情:

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";
  1. print "\xE1\x{2013}\xE1";   # Wide char! C3 A1 E2 80 93 C3 A1
    

    Perl会通知您忘记编码,警告您并打印使用UTF-8编码的字符串。

  2. print "\xE1";               # E1
    

    Perl无法知道您忘记了编码,因此会打印您要求打印的内容。

  3. print "\x{2013}";           # Wide char! E2 80 93
    

    Perl会通知您忘记编码,警告您并打印使用UTF-8编码的字符串。


脚注

  1. 存储格式的选择(由返回is_utf8)应该永远不会生效。print正确地不受此影响。

    utf8::downgrade( my $d = chr(0xE1) );  print($d);  # UTF8=0 prints E1
    utf8::upgrade(   my $u = chr(0xE1) );  print($u);  # UTF8=1 prints E1
    

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么字符串在python shell和解释器窗口中的打印方式不同?

来自分类Dev

换行符更改从文件读取的字符串在C ++中的打印方式

来自分类Dev

字符串在Visual Studio和gcc中的打印方式不同

来自分类Dev

在Python中将utf-8字符串拆分为字节

来自分类Dev

在ICU中打印UTF-8字符串

来自分类Dev

为什么在Julia中不建议对UTF8字符串进行索引?

来自分类Dev

在Windows的Sublime Text控制台中打印utf8字符串

来自分类Dev

如何在Windows上将UTF-8字符串打印到std :: cout?

来自分类Dev

在遍历UTF-8字符串时,什么决定了字符的位置?

来自分类Dev

打印UTF-16字符串

来自分类Dev

为什么UTF-8字符串没有字节顺序问题?

来自分类Dev

Perl中的JSON编码/解码utf8字符串

来自分类Dev

在Perl中对utf8字符串使用“排序”

来自分类Dev

为什么UTF-8字符串不等于Ruby 2.0中的等效ASCII-8BIT字符串?

来自分类Dev

打印方法“无效语法”反转字符串

来自分类Dev

清理错误的UTF-8字符串

来自分类Dev

UTF8字符串为int

来自分类Dev

MySQL比较UTF-8字符串

来自分类Dev

Python反转UTF-8字符串

来自分类Dev

如何使用Node.js在控制台中打印utf8字符串

来自分类Dev

是否可以在Windows控制台中使用Boost和STL打印UTF-8字符串?

来自分类Dev

utf16字符串作为utf8字符串的长度

来自分类Java

拆分UTF-8字符串的正确方法

来自分类Dev

使用字素与拆分的UTF-8字符串数组

来自分类Java

在Java / Android中找出UTF-8字符串中的字符数

来自分类Dev

在perl上打印包含utf-8字节序列的字符串

来自分类Dev

将UTF-8字符串转换为可读字符串

来自分类Dev

Python:将utf-8字符串转换为字节字符串

来自分类Dev

如何使用UTF-8字符串检查golang中的字符值?

Related 相关文章

热门标签

归档