sid*_*com 7 unicode perl warnings character try-catch
我怎么能抓住"Unicode非字符0xffff是非法的交换" - 警告?
#!/usr/bin/env perl
use warnings;
use 5.012;
use Try::Tiny;
use warnings FATAL => qw(all);
my $character;
try {
$character = "\x{ffff}";
} catch {
die "---------- caught error ----------\n";
};
say "something";
Run Code Online (Sandbox Code Playgroud)
输出:
# Unicode non-character 0xffff is illegal for interchange at ./perl1.pl line 11.
Run Code Online (Sandbox Code Playgroud)
tch*_*ist 14
我会假设你实际上并不想"抓住"这个警告,而是为了生存或忽略它.如果你真的想抓住它,那么可能有更简单的方法来做到这一点.
但首先要知道的是,没有非法代码点,只有代码点对交换无效.
您只需no warnings "utf8"
在需要使用完整Unicode范围(或更多)的范围内使用a . 没有必要使用eval
这个.所需要的只是一个范围警告抑制.即使在新的perls上也没有必要.
所以不是这样的:
$char = chr(0xFFFE);
Run Code Online (Sandbox Code Playgroud)
写(在旧的perls上):
$char = do { no warnings "utf8"; chr(0xFFFE) };
Run Code Online (Sandbox Code Playgroud)
这也是涉及这样一个角色的模式匹配的情况:
$did_match = do { no warnings "utf8" ; $char =~ $char);
Run Code Online (Sandbox Code Playgroud)
根据你的perl的年龄大小,取决于你的perl的新程度,会引起警告或致命.
您只能在以这种方式重要的版本上禁用与utf8相关的警告:
no if $^V < 5.13.9, qw<warnings utf8>;
Run Code Online (Sandbox Code Playgroud)
真正有趣的是,他们(阅读:Perl5 Porters,特别是Karl Williamson)已经修复了需要一个no warnings "utf8"
警卫才能使用任何代码点的错误.它只是您可能必须小心的输出.看:
% perl5.10.0 -Mwarnings=FATAL,all -E 'my $char = chr(0xFFFE); say "Ok"'
Unicode character 0xfffe is illegal at -e line 1.
% perl5.11.3 -Mwarnings=FATAL,all -E 'my $char = chr(0xFFFE); say "Ok"'
Unicode non-character 0xfffe is illegal for interchange at -e line 1.
% perl5.12.0 -Mwarnings=FATAL,all -E 'my $char = chr(0xFFFE); say "Ok"'
Unicode non-character 0xfffe is illegal for interchange at -e line 1.
% perl5.12.3 -Mwarnings=FATAL,all -E 'my $char = chr(0xFFFE); say "Ok"'
Unicode non-character 0xfffe is illegal for interchange at -e line 1.
% perl5.13.0 -Mwarnings=FATAL,all -E 'my $char = chr(0xFFFE); say "Ok"'
Unicode non-character 0xfffe is illegal for interchange at -e line 1.
% perl5.13.8 -Mwarnings=FATAL,all -E 'my $char = chr(0xFFFE); say "Ok"'
Unicode non-character 0xfffe is illegal for interchange at -e line 1.
% perl5.13.9 -Mwarnings=FATAL,all -E 'my $char = chr(0xFFFE); say "Ok"'
Ok
% perl5.13.10 -Mwarnings=FATAL,all -E 'my $char = chr(0xFFFE); say "Ok"'
Ok
Run Code Online (Sandbox Code Playgroud)
最安全的事情就是放在no warnings "utf8"
你需要的地方.但是没有必要eval
!
从5.13.10开始,因此在5.14中,有utf8警告的三个子类别:surrogate
对于UTF-16,nonchar
如下所述,non_unicode
对于supers,也在下面定义.
但是,您可能不希望在输出上抑制"非法交换"警告,因为这是真的.好吧,除非你使用Perl的"utf8"
编码,这与"UTF?8"
编码不同,奇怪的是.该"utf8"
编码laxer比正式的标准,因为它允许我们做更多有趣的事情,比我们所能,否则.
但是,当且仅当您拥有100%纯perl数据路径时,您仍然可以使用任何所需的代码点,包括最多为ᴍᴀxɪɴᴛ的非unicode代码点.那是32位机器上的0x7FFF_FFFF,在64位机器上有一些难以言表的巨大:0xFFFF_FFFF_FFFF_FFFF!那不仅仅是一个超级; 这是一个超级巨星!
% perl -Mwarnings -CS -E 'my $a = chr(0xFFFF_FFFF); say $a ' |
perl -Mwarnings -CS -nlE 'say "got ord ", ord'
Code point 0xFFFFFFFF is not Unicode, may not be portable at -e line 1.
got ord 4294967295
% perl -Mwarnings -CS -E 'no warnings "utf8"; my $a = chr(0xFFFF_FFFF); say $a' |
perl -Mwarnings -CS -nlE 'say "got ord ", ord'
got ord 4294967295
% perl -Mwarnings -CS -E 'no warnings "utf8"; my $a = chr(0xFFFF_FFFF_FFFF_FFFF); say $a' |
perl -Mwarnings -CS -nlE 'say "got ord ", ord'
Hexadecimal number > 0xffffffff non-portable at -e line 1.
got ord 18446744073709551615
% perl -Mwarnings -CS -E 'no warnings qw[ utf8 portable ]; my $a = chr(0xFFFF_FFFF_FFFF_FFFF); say $a ' |
perl -Mwarnings -CS -nlE 'say "got ord ", ord'
got ord 18446744073709551615
Run Code Online (Sandbox Code Playgroud)
请注意,在32位计算机上,最后一台计算机会产生以下结果:
Integer overflow in hexadecimal number at -e line 1.
got ord 4294967295
Run Code Online (Sandbox Code Playgroud)
有几个 - 实际上是相当多 - 不同类别的代码点,这些代码点对于交换是不合法的.
任何代码点 (ord(?????????) & 0xFFFE) == 0xFFFE
都是如此.这涵盖了所有可能平面中的最后两个代码点.因为它跨越17个平面,因此Unicode定义了34个这样的代码点.虽然它们是Unicode代码点,但它们不是字符.我们称之为Penults.他们属于nonchar
5.13.10或更高级别的警告级别.
32个代码点从U + FDD0开始.这些保证是非字符的,当然它们仍然是Unicode代码点.与之前的阴谋集一样,这些也属于nonchar
5.13.10或更高级别的警告级别.
1024个高代理和1024个低代理,这些代理被划分为slop,使得所有那些尝试使用UCS-2而不是UTF-8或UTF-32的哑系统都可以使用UTF-16.这削弱了有效Unicode代码点的范围,将它们限制为仅前21位.代理商仍然是代码点.它们只对交换无效,因为它们不能总是被脑死亡聪明的UTF-16正确表示.在5.13.10或更高版本下,这些由surrogate
警告子类控制.
除此之外,我们现在高于Unicode范围.我会称这些超级明星.在32位计算机上,您仍然有(10或11位)超出Unicode为您提供的标准21位.Perl可以使用这些就好了.这样可以在Perl程序中使用2**32个总代码点(好吧,至少2**31,因为有符号溢出).您获得了一百万个Unicode代码点,但是除了可以在Perl中使用的代码点之外,您还可以获得几十亿个超级代码点.如果您运行的是5.13.10或更高版本,则可以通过non_unicode
警告子类控制对这些内容的访问.
Perl仍然遵循有关Penults的规则甚至超级范围.在32位机器上有480个这样的Superpenults,而在64位机器上则更多.
如果你真的想以非便携式方式播放,那么如果你有64位的本地内存,那么你可以拥有超过超级优惠的32或33位.你现在有18个quintillion 446千万亿744万亿73亿7千7百万551千和616个字符.你有一个整体艾字节的独特码点!这远远超出了超级我将称之为Hypermegas.好的,因此它们不是非常便携,因为它们需要真正的64位平台.他们有点陌生,所以也许我们应该写那些scπέρμεγας 来吓跑人们.:)请注意,针对阴茎的规则仍然适用于hypermegas.
我写了一个小程序,证明这些代码点很酷.
testing Penults passed all 34 codepoints
testing Super_penults passed all 480 codepoints
testing Noncharacters passed all 32 codepoints
testing Low_surrogates passed all 1024 codepoints
testing High_surrogates passed all 1024 codepoints
testing Supers passed all 8 codepoints
testing ????????? passed all 10 codepoints
Run Code Online (Sandbox Code Playgroud)
注意:上面的最后一行显示了SO的地狱突出显示代码中的又一个愚蠢错误.请注意最后一个WɪᴋɪWᴏʀᴅ那个,那个\p{Greek}
,被排除在着色方案之外?这意味着他们只寻找大写的ASCII标识符. Trèspassé! 如果你不打算使用\p{Uppercase}
正确的东西,为什么还要接受ᴜɴɪᴄᴏᴅᴇ ?正如你在我的程序中看到的那样,我有一个@?????????
数组,我们ᴍᴏᴅᴇʀɴᴘʀᴏɢʀᴀᴍᴍɪɴɢhandles处理完全没问题.☺
我显然没有运行所有的超级或超级.在32位计算机上,您只能获得4个经过测试的超级计算机.我也没有测试任何超级成品.
这是测试程序,它在5.10及更高版本的所有版本上运行得很干净.
#!/usr/bin/env perl
#
# hypertest - show how to safely use code points not legal for interchange in Perl
#
# Tom Christiansen
# tchrist@perl.com
# Sat Feb 26 16:38:44 MST 2011
use utf8;
use 5.10.0;
use strict;
use if $] > 5.010, "autodie";
use warnings FATAL => "all";
use Carp;
binmode(STDOUT, ":utf8");
END { close STDOUT }
$\ = "\n";
sub ghex(_);
my @penults = map {
(0x01_0000 * $_) + 0xfffE,
(0x01_0000 * $_) + 0xfffF,
} 0x00 .. 0x10;
my @super_penults = map {
(0x01_0000 * $_) + 0xfffE,
(0x01_0000 * $_) + 0xfffF,
} 0x10 .. 0xFF;
my @low_surrogates = map { 0xDC00 + $_ } 0x000 .. 0x3FF;
my @high_surrogates = map { 0xD800 + $_ } 0x000 .. 0x3FF;
my @noncharacters = map { 0xFDD0 + $_ } 0x00 .. 0x1F;
my @supers = (
0x0011_0000, 0x0100_0000, 0x1000_0000, 0x1F00_0000,
0x1FFF_FFFF, 0x3FFF_FFFF, 0x7FFF_FFFF, 0x7FFF_FFFF,
);
# these should always work anywhere
my @????????? = (
0x8000_0000, 0xF000_0000,
0x3FFF_FFFF, 0xFFFF_FFFF,
);
####
# now we go fishing for 64-bit ?????????
####
eval q{
use warnings FATAL => "overflow";
no warnings "portable";
push @????????? => (
0x01_0000_0000,
0x01_FFFF_FF00,
);
};
eval q{
use warnings FATAL => "overflow";
no warnings "portable";
push @????????? => (
0x0001_0000_0000_0000,
0x001F_0000_0000_0000,
0x7FFF_FFFF_FFFF_FFFF,
0xFFFF_FFFF_FFFF_FFFF,
);
};
# more than 64??
eval q{
use warnings FATAL => "overflow";
no warnings "portable";
push @????????? => (
0x01_0001_0000_0000_0000,
0x01_7FFF_FFFF_FFFF_FFFF,
0x01_FFFF_FFFF_FFFF_FFFF,
);
1;
};
my @testpairs = (
penults => \@penults,
super_penults => \@super_penults,
noncharacters => \@noncharacters ,
low_surrogates => \@low_surrogates,
high_surrogates => \@high_surrogates,
supers => \@supers,
????????? => \@?????????,
);
while (my($name, $aref) = splice(@testpairs, 0, 2)) {
printf "testing %-20s", ucfirst $name;
my(@passed, @failed);
for my $codepoint (@$aref) {
use warnings FATAL => "all";
my $char = do {
# next line not needed under 5.13.9 or better: HURRAY!
no warnings "utf8";
chr(0xFFFF) && chr($codepoint);
};
my $regex_ok = do {
# next line not needed under 5.13.9 or better: HURRAY!
no warnings "utf8";
$char =~ $char;
1;
};
my $status = defined($char) && $regex_ok;
push @{ $status ? \@passed : \@failed }, $codepoint;
}
my $total = @$aref;
my $passed = @passed;
my $failed = @failed;
given($total) {
when ($passed) { print "passed all $total codepoints" }
when ($failed) { print "failed all $total codepoints" }
default {
print "of $total codepoints, failed $failed and passed $passed";
my $flist = join(", ", map { ghex } @failed);
my $plist = join(", ", map { ghex } @passed);
print "\tpassed: $plist";
print "\tfailed: $flist";
}
}
}
sub ghex(_) {
my $num = shift();
my $hex = sprintf("%X", $num);
return $hex if length($hex) < 5;
my $flip = reverse $hex;
$flip =~ s<
( \p{ahex} \p{ahex} \p{ahex} \p{ahex} )
(?= \p{ahex} )
(?! \p{ahex}* \. )
><${1}_>gx;
return "0x" . reverse($flip);
}
Run Code Online (Sandbox Code Playgroud)