我想知道为什么大多数使用 Perl 构建的现代解决方案默认不启用UTF-8。
我知道核心 Perl 脚本存在许多遗留问题,可能会破坏一些东西。但是,从我的角度来看,在 21世纪,大型新项目(或具有大视野的项目)应该从头开始使他们的软件 UTF-8 证明。我仍然没有看到它发生。例如,Moose启用严格和警告,但不启用Unicode。Modern::Perl也减少了样板文件,但没有 UTF-8 处理。
为什么?在 2011 年的现代 Perl 项目中是否有一些理由避免使用 UTF-8?
评论@tchrist 太长了,所以我在这里添加它。
好像我没有说清楚。让我尝试添加一些东西。
tchrist 和我看到的情况非常相似,但我们的结论完全相反。我同意,Unicode 的情况很复杂,但这就是为什么我们(Perl 用户和编码人员)需要一些层(或 pragma)来使 UTF-8 处理变得像现在一样容易。
tchrist 指出了许多要涵盖的方面,我会阅读并思考几天甚至几周。不过,这不是我的观点。 tchrist 试图证明没有一种方法可以“启用 UTF-8”。我没有太多的知识可以与之争论。所以,我坚持活生生的例子。
我玩弄了Rakudo,而 UTF-8 就在 我需要的地方 。我没有任何问题,它只是工作。也许在更深的地方存在一些限制,但一开始,我测试的所有东西都按预期工作。
这不应该是现代 Perl 5 的目标吗?我更强调一点:我并不是建议将 UTF-8 作为核心 Perl 的默认字符集,我建议那些开发 新* 项目的人可以 快速触发它。 *
另一个例子,但语气更消极。框架应该使开发更容易。几年前,我尝试过 Web 框架,但因为“启用 UTF-8”太晦涩难懂而将它们扔掉了。 2 相同的问题: _如何使 Mason2 UTF-8 干净? 因此,它是一个相当新的框架,但将其与 UTF-8 一起使用需要深入了解其内部结构。它就像一个大红色标志:停止,不要使用我!
我真的很喜欢 Perl。但是处理Unicode是痛苦的。我仍然发现自己在靠墙奔跑。 tchrist 以某种方式是对的,它回答了我的问题:新项目不吸引 UTF-8,因为它在 Perl 5 中太复杂了。
将您的PERL_UNICODE变量设置为AS. 这使得所有 Perl 脚本都解码@ARGV为 UTF-8 字符串,并将 stdin、stdout 和 stderr 的所有三个编码设置为 UTF-8。这两个都是全局效应,而不是词汇效应。
PERL_UNICODE
AS
@ARGV
在您的源文件(程序、模块、库、dohickey)的顶部,通过以下方式突出声明您正在运行 perl 版本 5.12 或更高版本:
do
use v5.12; # minimal for unicode string feature
use v5.14; # optimal for unicode string feature
启用警告,因为之前的声明只启用了限制和特性,而不是警告。我还建议将 Unicode 警告提升为异常,因此请同时使用这两行,而不仅仅是其中之一。但是请注意,在 v5.14 下,utf8警告类包括其他三个可以单独启用的子警告:nonchar、surrogate和non_unicode。这些您可能希望对其施加更大的控制。
utf8
nonchar
surrogate
non_unicode
use warnings;
use warnings qw( FATAL utf8 );
声明这个源单元被编码为 UTF-8。尽管曾几何时这个 pragma 做了其他事情,但现在它只为这个单一的目的服务,而没有其他目的:
use utf8;
声明任何 在这个词法范围内但不在其他地方 打开文件句柄的东西都是假设该流是用 UTF-8 编码的,除非你另有说明。这样您就不会影响其他模块或其他程序的代码。
use open qw( :encoding(UTF-8) :std );
通过 启用命名字符\N{CHARNAME}。
\N{CHARNAME}
use charnames qw( :full :short );
如果您有DATA句柄,则必须显式设置其编码。如果你希望这是 UTF-8,那么说:
DATA
binmode(DATA, ":encoding(UTF-8)");
当然,您最终可能会发现自己关心的其他问题没有尽头,但这些足以接近国家的目标,即“让一切都与 UTF 一起工作”8”,尽管对这些问题的感觉有所减弱条款。
另一个编译指示虽然与 Unicode 无关,但它是:
use autodie;
这些天我自己的样板往往看起来像这样:
use 5.014; use utf8; use strict; use autodie; use warnings; use warnings qw< FATAL utf8 >; use open qw< :std :utf8 >; use charnames qw< :full >; use feature qw< unicode_strings >; use File::Basename qw< basename >; use Carp qw< carp croak confess cluck >; use Encode qw< encode decode >; use Unicode::Normalize qw< NFD NFC >; END { close STDOUT } if (grep /\P{ASCII}/ => @ARGV) { @ARGV = map { decode("UTF-8", $_) } @ARGV; } $0 = basename($0); # shorter messages $| = 1; binmode(DATA, ":utf8"); # give a full stack dump on any untrapped exceptions local $SIG{__DIE__} = sub { confess "Uncaught exception: @_" unless $^S; }; # now promote run-time warnings into stack-dumped # exceptions *unless* we're in an try block, in # which case just cluck the stack dump instead local $SIG{__WARN__} = sub { if ($^S) { cluck "Trapped warning: @_" } else { confess "Deadly warning: @_" } }; while (<>) { chomp; $_ = NFD($_); ... } continue { say NFC($_); } __END__
说“Perl 应该 [以某种方式!] 默认情况下启用 Unicode”甚至没有开始考虑在某些罕见和孤立的情况下说足够多的东西,甚至有点用处。Unicode 不仅仅是一个更大的字符库。这也是这些角色如何以多种方式相互作用的方式。
即使是(某些)人似乎认为他们想要的头脑简单的最小措施也保证会严重破坏数百万行代码,这些代码没有机会“升级”到你漂亮的新美丽新世界现代性。
这比人们想象的要复杂得多。在过去的几年里,我一直在思考这个巨大的问题。我很想被证明我错了。但我不认为我是。从根本上说,Unicode 比您想强加给它的模型更复杂,而且这里的复杂性是您永远无法掩盖的。如果您尝试,您将破坏您自己的代码或其他人的代码。在某些时候,您只需要分解并了解 Unicode 是什么。你不能假装它不是。
不遗余力地让 Unicode 变得简单,远远超过我用过的任何其他东西。如果您认为这很糟糕,请尝试其他方法一段时间。然后回到:要么你会回到一个更美好的世界,要么你会带来同样的知识,这样我们就可以利用你的新知识让在这些事情上做得更好。
正如你所说,至少,这里有一些东西似乎是 “默认启用 Unicode”所必需的:
use utf8
export PERL5OPTS=-Mutf8
binmode(DATA, ":encoding(UTF-8)")
export PERL_UNICODE=A
perl -CA
export PERL5OPTS=-CA
export PERL_UNICODE=S
I
O
E
perl -CS
export PERL_UNICODE=D
i
o
export PERL5OPTS=-CD
-CSAD
export PERL5OPTS=-Mopen=:utf8,:std
export PERL5OPTS=-Mwarnings=FATAL,utf8
binmode
:encoding(UTF-8)
:utf8
use feature "unicode_strings"
export PERL5OPTS=-Mfeature=unicode_strings
uc("\xDF") eq "SS"
"\xE9" =~ /\w/
export PERL5OPTS=-Mv5.12
export PERL5OPTS=-Mcharnames=:full,:short,latin,greek
Unicode::Normalize
export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD
eq
ne
lc
cmp
sort
@a = sort @b
@a = Unicode::Collate->new->sort(@b)
export PERL5OPTS=-MUnicode::Collate
printf
write
Unicode::GCString
Unicode::LineBreak
\d+
Unicode::UCD::num
a-z
A-Z
m//
s///
tr///
\p{Lu}
[A-Za-z]
\p{Upper}
\p{Lowercase}
\p{Lower}
\p{Ll}
\p{Lowercase_Letter}
[a-zA-Z]
\pL
\p{Letter}
\p{Alphabetic}
/[\$\@\%]\w+/
/[\$\@\%]\p{IDS}\p{IDC}*/
\h
\v
\s
[\h\v]
\n
\r\n
\R
Unicode::Collate->new(level => 1)->cmp($a, $b)
match
substr
Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b)
Unicode::Collate::->new(level => 1)->eq("d", "ð")
Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð")
[aeiou]
(?=[aeiou])\X)
这还不是全部。人们对 Unicode 有一百万个被打破的假设。在他们理解这些事情之前,他们的🐪代码将被破坏。
$/
lc(uc($s)) eq $s
uc(lc($s)) eq $s
uc("σ")
uc("ς")
"Σ"
lc("Σ")
"ª"
"ᵃ"
"ᴬ"
\p{Mark}
\p{Diacritic}
\p{GC=Dash_Punctuation}
\p{Dash}
\X
"\x{FFFF}"
"\xC0\x80"
>
<
X
Y
XY
\p{Math}
\w
^
~
ü
₨
\p{InLatin}
\p{Latin}
$FIRST_LETTER
$LAST_LETTER
[${FIRST_LETTER}-${LAST_LETTER}]
?
ls
readdir
/s/i
"S"
"s"
\PM\pM*
我不知道你能得到比我写的更多的“ 中的默认 Unicode”。嗯,是的,我愿意:你也应该使用Unicode::Collateand Unicode::LineBreak。而且可能更多。
Unicode::Collate
如您所见,您确实需要担心太多的 Unicode 问题,以至于永远不会存在“默认为 Unicode”之类的东西。
你会发现,就像我们在 5.8 中所做的那样,根本不可能将所有这些东西强加于从一开始就没有正确设计的代码上。你善意的自私刚刚毁了整个世界。
即使你这样做了,仍然存在需要大量思考才能正确解决的关键问题。没有可以翻转的开关。只有大脑,我的意思是真正的大脑,在这里就足够了。有很多东西你必须学习。以手动打字机为模,你根本不能希望在无知中偷偷溜走。这是 21ˢᵗ 世纪,你不能因为故意无知而希望 Unicode 消失。
你必须学习它。时期。“一切正常”永远不会那么容易,因为这将保证很多事情都行不通——这使得永远有办法“让一切都正常”的假设无效。
您可能能够为极少数且非常有限的操作获得一些合理的默认值,但并非没有考虑比我认为的更多的事情。
举个例子,规范排序会引起一些真正的麻烦。 "\x{F5}" ‘õ’、"o\x{303}" ‘õ’、"o\x{303}\x{304}" ‘ȭ’和"o\x{304}\x{303}" ‘ō̃’都应该匹配‘õ’,但你到底要怎么做呢?这比看起来要难,但这是您需要考虑的事情。
"\x{F5}"
"o\x{303}"
"o\x{303}\x{304}"
"o\x{304}\x{303}"
如果有一件事,我知道Perl,它就是它的unicode比特做了什么,而不是这样做,我保证你: “ ᴛʜᴇʀᴇᴛʜᴇʀᴇsɴᴏuɴɪᴄᴏᴅᴇɴɪᴄᴏᴅᴇᴍᴀɢɪᴄᴍᴀɢɪᴄʙᴜʟʟᴇᴛʙᴜʟʟᴇᴛ
你不能仅仅改变一些默认值就可以一帆风顺。确实,我运行 时PERL_UNICODE设置为"SA",但仅此而已,甚至主要用于命令行的东西。对于实际工作,我会经历上面列出的所有步骤,并且非常、非常小心。
"SA"