使用unicode的Perl ord和chr
令我恐惧的是,我刚刚发现使用unicode的Perl ord和chr,perl,unicode,Perl,Unicode,令我恐惧的是,我刚刚发现chr不能与Unicode一起工作,尽管它做了一些事情。手册页非常清晰 返回字符集中由该数字表示的字符。例如,在ASCII或Unicode中,chr(65)”是“A”,而chr(0x263a)是Unicode笑脸 事实上,我可以使用 perl -e 'print chr(0x263a)' 但是像chr(0x00C0)这样的东西不起作用。我看到我的perl v5.10.1有点过时,但是当我在源代码中粘贴各种奇怪的字母时,一切都很好 我尝试过一些有趣的事情,比如使用utf8
chr
不能与Unicode一起工作,尽管它做了一些事情。手册页非常清晰
返回字符集中由该数字表示的字符。例如,在ASCII或Unicode中,chr(65)”是“A”,而chr(0x263a)是Unicode笑脸
事实上,我可以使用
perl -e 'print chr(0x263a)'
但是像chr(0x00C0)
这样的东西不起作用。我看到我的perl v5.10.1有点过时,但是当我在源代码中粘贴各种奇怪的字母时,一切都很好
我尝试过一些有趣的事情,比如使用utf8
和使用编码“utf8”
,我没有尝试过使用v5.12
和使用功能“unicode\u字符串”
等有趣的事情,因为它们不适用于我的版本,我一直在玩弄编码::解码
来发现我不需要解码,因为我没有字节数组解码。我阅读了比以往更多的文档,发现了很多有趣的东西,但并没有什么帮助。它看起来像是一种解决方案,但并没有给出可用的解决方案。此外,我不关心整个字符串语义,我所需要的只是一个简单的函数
那么,我如何将一个数字转换成一个由与其对应的单个字符组成的字符串,以使例如real_chr(0xC0)eq“À”
保持不变
我得到的第一个答案解释了IO的一切,但我仍然不明白为什么
#!/usr/bin/perl -w
use strict;
use utf8;
use encoding 'utf8';
print chr(0x00C0) eq 'À' ? 'eq1' : 'ne1', " - ", chr(0x263a) eq '☺' ? 'eq1' : 'ne1', "\n";
print 'À' =~ /\w/ ? "match1" : "no_match1", " - ", chr(0x00C0) =~ /\w/ ? "match2" : "no_match2", "\n";
印刷品
ne1 - eq1
match1 - no_match2
这意味着手动输入的“À”
不同于chr(0x00C0)
。此外,前者是单词组成字符(正确!),而后者不是(但应该是!)。首先
perl -le'print chr(0x263A);'
Perl甚至告诉您:
Wide character in print at -e line 1.
这不符合“工作”的条件。因此,尽管它们在如何无法提供您想要的方面存在差异,但以下两项都不能提供您想要的:
perl -le'print chr(0x263A);'
perl -le'print chr(0x00C0);'
要正确地输出这些Unicode代码点的UTF-8编码,需要告诉Perl使用UTF-8编码Unicode点
$ perl -le'use open ":std", ":encoding(UTF-8)"; print chr(0x263A);'
☺
$ perl -le'use open ":std", ":encoding(UTF-8)"; print chr(0x00C0);'
À
现在来谈谈“为什么” 文件句柄只能传输字节,因此除非您另有说明,否则Perl文件句柄需要字节。这意味着您提供给
打印
的字符串只能包含字节,或者换句话说,它不能包含超过255个字符。输出正是您提供的:
$ perl -e'print map chr, 0x00, 0x65, 0xC0, 0xF0' | od -t x1
0000000 00 65 c0 f0
0000004
这很有用。这与您想要的不同,但这并不意味着它是错的。如果您想要不同的东西,只需要告诉Perl您想要什么
通过添加一个:encoding
层,句柄现在需要一个Unicode字符字符串,或者我称之为“text”。该层告诉Perl如何将文本转换为字节
$ perl -e'
use open ":std", ":encoding(UTF-8)";
print map chr, 0x00, 0x65, 0xC0, 0xF0, 0x263a;
' | od -t x1
0000000 00 65 c3 80 c3 b0 e2 98 ba
0000011
您认为
chr
不知道或不关心Unicode的权利。像length
、substr
、ord
和reverse
,chr
实现了一个基本的字符串函数,而不是Unicode函数。这并不意味着它不能用于文本字符串。正如您所看到的,问题不在于chr
但是在构建字符串之后,您对它所做的操作
字符是字符串的元素,字符是数字。这意味着字符串只是一个数字序列。是否将这些数字视为Unicode码点(文本)、压缩IP地址或温度测量值完全取决于您和将字符串传递到的函数
下面是一些运算符的示例,它们为作为操作数接收的字符串赋值:
需要一个Unicode码点字符串m/
需要一个字节序列,该序列表示结构中的connect
sockaddr\u
带句柄,不带打印
需要一个字节序列:编码
需要一个Unicode码点序列使用带有
:编码的句柄打印
- 等
那个么我怎样才能把一个数字转换成一个由对应的单个字符组成的字符串,比如real_chr(0xC0)eq‘À’保持不变呢?
chr(0xC0)eq‘À’
确实有效。您是否记得告诉Perl您使用UTF-8对源代码进行了编码,方法是使用使用utf8;
?如果您没有告诉Perl,Perl实际上会在RHS上看到一个两个字符的字符串
关于您添加的问题:
编码
杂注存在问题。我建议不要使用它。相反,请使用
use open ':std', ':encoding(UTF-8)';
这将解决其中一个问题。您遇到的另一个问题是
chr(0x00C0) =~ /\w/
这是一个已知的bug,出于向后兼容性的原因,故意将其保留下来。也就是说,除非您请求更新该语言的版本,如下所示:
use 5.014; # use 5.012; *might* suffice.
最早可追溯到5.8的解决方案:
my $x = chr(0x00C0);
utf8::upgrade($x);
$x =~ /\w/
@D.Shawley:Linux2.6.32-42-generic,x86_64 GNU/Linux,Ubuntu 10.4,所以utf8是本地的。Áis
c381的utf8八位字节序列是ISO-8859-1的代码点。我的Perlfu有点弱,或者我会提出一个答案。有些文档在这方面很弱,但是UTF-8实现,即使在后面的Perl 5.10.1中也是相当不错的strong。我建议您在使用Perl中的Unicode之前先阅读一下。在您的例子中,chr
不是问题所在,而是您没有为UTF-8编码和解码字符串。如果您要输出UTF-8(或任何其他编码),您的字符串需要首先转换为八位字节。@ikegami:删除它会将输出更改为eq1-eq1;match1-no_match2
。因此,我有两个相等的字符串,其中只有一个匹配。在Perl 5.14之前的任何版本中,Unicode正则表达式的支持都被破坏。在Perl 5.14中,您的第二个正则表达式通过如果使用编码
和附加的/u
修饰符。如果需要更手动的解决方案,也可以使用编码qw(编码);打印编码