为什么现代Perl在默认情况下避免使用UTF-8? [英] Why does modern Perl avoid UTF-8 by default?

查看:7
本文介绍了为什么现代Perl在默认情况下避免使用UTF-8?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道为什么大多数使用Perl构建的现代解决方案在默认情况下不启用UTF-8

我知道核心Perl脚本有许多遗留问题,在这些问题上它可能会破坏一些东西。但是,在我看来,在21世纪st世纪,大型的新项目(或有远见的项目)应该从零开始对他们的软件进行UTF-8验证。尽管如此,我仍认为这不会发生。例如,Moose启用严格和警告,但不启用UnicodeModern::Perl也减少了样板,但没有UTF-8处理。

为什么?在2011年的现代Perl项目中,有什么理由避免使用UTF-8吗?


评论@tchrist太长,所以我在此添加它。

我似乎没有说清楚。让我试着添加一些东西。

tchrist我认为情况非常相似,但我们的结论完全相反。我同意,Unicode的情况很复杂,但这就是为什么我们(Perl用户和程序员)需要一些层(或杂注)来使UTF-8处理像现在一样简单。

tchrist指出了许多方面要涵盖,我会阅读并思考它们几天甚至几周。不过,这不是我的意思。tchrist试图证明"启用UTF-8"不是唯一的方法。我没有那么多的知识来反驳这一点。因此,我坚持使用活生生的例子。

我玩了Rakudo,UTF-8就在我需要的时候。我没有遇到任何问题,它只是起作用了。也许有一些更深层次的限制,但在开始时,我测试的所有东西都像我预期的那样工作。

这不也应该是现代Perl ;5的目标吗?我要强调的是:我并不是建议将UTF-8作为核心Perl的默认字符集,我建议对于那些开发项目的人,可以通过快速触发它

另一个例子,但语气更负面。框架应该让开发变得更容易。几年前,我尝试过Web框架,但因为"启用UTF-8"太晦涩难懂而把它们扔掉了。我没有找到如何以及在哪里挂接Unicode支持。这太耗时了,我发现走老路更容易。现在我在这里看到了处理Mason2:How to make Mason2 UTF-8 clean?的赏金。因此,它是一个相当新的框架,但将其与UTF-8一起使用需要对其内部有深刻的了解。它就像一个大的红色标志:停下来,不要利用我!

我非常喜欢Perl。但与Unicode打交道是痛苦的。我仍然发现自己在碰壁。在某种程度上tchrist是正确的,它回答了我的问题:新项目不会吸引UTF-8,因为它在Perl ;5中太复杂了。

推荐答案

𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩:𝟕𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨

  1. PERL_UNICODEen变量设置为AS。这会使所有Perl脚本将@ARGV解码为UTF-8字符串,并将stdin、stdout和stderr这三个字符串的编码设置为UTF-8。这两个都是全局效果,而不是词法效果。

  2. 在源文件(程序、模块、库,doHickey)的顶部,突出显示您正在运行Perl版本5.12或更高版本,方法是:

    use v5.12;  # minimal for unicode string feature
    use v5.14;  # optimal for unicode string feature
    
  3. 启用警告,因为前面的声明只启用限制和功能,不启用警告。我还建议将Unicode警告提升为异常,因此要同时使用这两行代码,而不是只使用其中一行。但是请注意,在v5.14中,utf8警告类包括另外三个子警告,它们都可以单独启用:noncharsurrogatenon_unicode。您可能希望对它们施加更大的控制。

    use warnings;
    use warnings qw( FATAL utf8 );
    
  4. 声明此源单元编码为UTF-8。虽然很久以前此杂注还做其他事情,但现在它只有一个单一用途,而不是其他用途:

    use utf8;
    
  5. 声明在这个词法作用域内打开文件句柄而不是在其他地方的任何东西都假定该流是以UTF-8编码的,除非您另有说明。这样您就不会影响其他模块或其他程序代码。

    use open qw( :encoding(UTF-8) :std );
    
  6. 通过N{CHARNAME}启用命名字符。

    use charnames qw( :full :short );
    
  7. 如果您有DATA句柄,则必须显式设置其编码。如果您希望它是UTF-8,则说:

    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",至少需要满足以下条件:

  1. 默认情况下,所有🐪源代码都应该是UTf-8。您可以使用use utf8export PERL5OPTS=-Mutf8

  2. 🐪DATA句柄应为Utf-8。您必须按程序包执行此操作,如binmode(DATA, ":encoding(UTF-8)")所示。

  3. 🐪脚本的程序参数在默认情况下应理解为UTf-8。export PERL_UNICODE=A、或perl -CA、或export PERL5OPTS=-CA

  4. 标准输入、输出和错误流应默认为UTF-8。export PERL_UNICODE=S,或仅部分IO和/或E。这类似于perl -CS

  5. 除非另有声明,否则由🐪打开的任何其他句柄都应被视为Utf-8;export PERL_UNICODE=D或对其中特定句柄使用ioexport PERL5OPTS=-CD将起作用。这使得-CSAD对所有人都适用。

    /li>
  6. 覆盖两个基本内容以及您用export PERL5OPTS=-Mopen=:utf8,:std打开的所有流。请参阅uniquote

  7. 您不想错过UTF-8编码错误。尝试export PERL5OPTS=-Mwarnings=FATAL,utf8。并确保您的输入流始终是binmode:encoding(UTF-8),而不仅仅是到:utf8

  8. 128-255之间的代码点应该被🐪理解为对应的unicode代码点,而不仅仅是没有属性的二进制值。use feature "unicode_strings"export PERL5OPTS=-Mfeature=unicode_strings。这将使uc("xDF") eq "SS""xE9" =~ /w/。简单的export PERL5OPTS=-Mv5.12或更好的版本也能实现这一点。

  9. 默认情况下未启用命名的Unicode字符,因此添加export PERL5OPTS=-Mcharnames=:full,:short,latin,greek或类似的字符。请参阅uninamestcgrep

  10. 您几乎总是需要访问the standard Unicode::Normalize module各种类型分解中的函数。export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD,然后始终通过NFD运行传入内容,并从NFC运行传出内容。据我所知,目前还没有这些I/O层,但请参阅nfcnfdnfkdnfkc

  11. 在🐪中使用eqnelccmpsort、&;c&;cc进行字符串比较总是错误的。因此,您需要@a = Unicode::Collate->new->sort(@b)而不是@a = sort @b。不妨把它加到你的export PERL5OPTS=-MUnicode::Collate里。您可以缓存密钥以进行二进制比较。

  12. printfwrite等🐪内置代码对unicode数据做了错误的处理。对于前者,您需要使用the Unicode::GCString module,对于后者,您还需要使用the Unicode::LineBreak module。请参阅uwcunifmt

  13. 如果希望它们算作整数,则必须通过the Unicode::UCD::num function运行d+捕获,因为🐪内置的ATOI(3)当前不够智能。

  14. 您将在👽文件系统上遇到文件系统问题。一些文件系统静默地强制转换为NFC;其他文件系统静默地强制转换为NFD。而其他人仍然在做其他的事情。一些人甚至完全忽视了这一问题,这导致了更大的问题。因此,您必须进行自己的NFC/NFD处理才能保持正常。

    /li>
  15. 您所有涉及a-zA-Z以及此类的🐪代码都必须更改,包括m//s///tr///。它应该是一个尖叫的红旗,表明你的代码被破解了。但目前还不清楚它必须如何改变。获得合适的房产,并了解它们的案例,比你想象的要难。我每天都使用unicharsuniprops

  16. 使用p{Lu}的代码几乎和使用[A-Za-z]的代码一样错误。您需要改用p{Upper},并且知道原因。是的,p{Lowercase}p{Lower}p{Ll}p{Lowercase_Letter}不同。

  17. 使用[a-zA-Z]的代码更差。它不能使用pLp{Letter};它需要使用p{Alphabetic}。你知道,并不是所有的字母都是字母!

  18. 如果您正在使用/[$@\%]w+/查找🐪变量,那么就有问题了。您需要查找/[$@\%]p{IDS}p{IDC}*/,即使这样也没有考虑标点符号变量或包变量。

  19. 如果要检查空格,则应在hv之间进行选择,具体取决于。而且您永远不应该使用s,因为并不意味着[hv],这与人们的普遍看法相反。

  20. 如果您使用 作为线边界,甚至 ,那么您就做错了。您必须使用R,这是不同的!

  21. 如果您不知道何时以及是否调用Unicode::Stringprep,那么您最好学习一下。

  22. 不区分大小写的比较需要检查两个字母是否相同,无论它们的变音符号是什么。最简单的方法是使用standard Unicode::Collate模块。Unicode::Collate->new(level => 1)->cmp($a, $b)。还有eq方法之类的,您可能也应该学习matchsubstr方法。与🐪内置功能相比,这些功能具有明显的优势。

    /li>
  23. 有时这仍然不够,您需要the Unicode::Collate::Locale模块,如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", " ð")为假。同样,如果您不使用区域设置,或者如果您使用英语区域设置,则"ae"和"æ"是eq,但它们在冰岛语区域设置中是不同的。这次又是什么?我告诉你,这很难。您可以使用ucsort来测试其中一些内容。

  24. 考虑如何匹配字符串"niño"中的模式CVCV(辅音、元音、辅音、元音)。它的NFD形式--你最好记得把它放进去--变成了"NINX{303}O"。现在你要做什么?即使假装元音是[aeiou](顺便说一句,这是错误的),您也不能做类似(?=[aeiou])X)的事情,因为即使在NFD中,像‘ø’这样的代码点也不会分解!但是,使用我刚才展示的UCA比较,它将测试为等于‘o’。你不能依赖NFD,你必须依赖UCA。


💩𝔸𝕤𝕤𝕦𝕞𝕖𝔹𝕣𝕠𝕜𝕖𝕟𝕟𝕖𝕤𝕤💩


这还不是全部。人们对Unicode有一百万种错误的假设。在他们了解这些事情之前,他们的🐪代码将被破解。

  1. 假定可以在不指定编码的情况下打开文本文件的代码已损坏。

  2. 假定默认编码为某种本机平台编码的代码已损坏。

  3. 假设日语或中文网页在UTF-16中占用的空间比UTF-8中的少的代码是错误的。

  4. 假定Perl内部使用UTF-8的代码是错误的。

  5. 假定编码错误将始终引发异常的代码是错误的。

  6. 假定Perl代码点限制为0x10_FFFF的代码是错误的。

    /li>
  7. 假定您可以将$/设置为可与任何有效的行分隔符一起使用的代码是错误的。

  8. 假定案例折叠的往返相等的代码,如lc(uc($s)) eq $suc(lc($s)) eq $s,是完全错误的。认为uc("σ")uc("ς")都是"Σ",但lc("Σ")不可能同时返回这两个值。

  9. 假定每个小写代码点都有一个明显的大写代码点或反之亦然的代码失败了。例如,"ª"是没有大写的小写字母;而"ᵃ""ᴬ"都是字母,但都不是小写字母;但是,它们都是小写代码点,没有对应的大写版本。明白了吗?它们不是p{Lowercase_Letter},尽管它们既是p{Letter}又是p{Lowercase}

  10. 假定更改大小写不会更改字符串长度的代码已损坏。

  11. 假定只有两种情况的代码中断。还有标题大写。

  12. 假定只有字母大小写的代码已中断。事实证明,除了字母之外,数字、符号甚至标记都有大小写。事实上,改变大小写甚至可以使某些东西改变其主要的一般范畴,比如p{Mark}变成p{Letter}。它还可以使其从一个脚本切换到另一个脚本。

  13. 假定大小写从不依赖于区域设置的代码已损坏。

  14. 假定Unicode提供有关POSIX区域设置的图表的代码已损坏。

  15. 假定您可以删除变音符号以获得基本的ASCII字母的代码是邪恶的、静止的、破碎的、大脑受损的、错误的和死刑的正当理由。

  16. 假定变音符号p{Diacritic}和标记p{Mark}是同一事物的代码已损坏。

  17. 假定p{GC=Dash_Punctuation}覆盖的范围与p{Dash}一样多的代码已损坏。

    /li>
  18. 假定破折号、连字符和减号是同一事物,或者每个都只有一个的代码是错误的。

  19. 假定每个代码点不超过一个打印列的代码已损坏。

  20. 假定所有p{Mark}字符占据零打印列的代码已中断。

  21. 假定看起来相似的字符也是的代码已损坏。

  22. 假定看起来不像的字符的代码已损坏。

  23. 假定一行中只有一个X可以匹配的代码点数量有限制的代码是错误的。

  24. 假定X永远不能以p{Mark}字符开头的代码是错误的。

  25. 假定X永远不能包含两个非p{Mark}字符的代码是错误的。

  26. 假定不能使用"x{FFFF}"的代码是错误的。

  27. 假定需要两个UTF-16(代理)代码单元的非BMP代码点将编码为两个单独的UTF-8字符(每个代码单元一个)的代码是错误的。不是:它编码为单个代码点。

  28. 将带有前导BOM的UTF-16或UTF-32代码转换为UTF-8的代码如果将BOM放在生成的UTF-8的开头,则代码将被中断。这太愚蠢了,工程师应该摘掉他们的眼皮。

  29. 假定CESU-8是有效UTF编码的代码是错误的。同样,认为将U+0000编码为"xC0x80"是UTF-8的代码也是错误的。这些家伙也应该接受眼皮治疗。

  30. 假定>等字符始终指向右侧而<始终指向左侧的代码是错误的,因为它们实际上并非如此。

  31. 假定如果先输出字符X,然后输出字符Y,则这些字符将显示为XY的代码是错误的。有时他们不会。

    /li>
  32. 认为ASCII代码足够好,可以正确书写英语的代码是愚蠢的、短视的、文盲的、破碎的、邪恶的和错误的。砍掉他们的头!如果这看起来太极端了,我们可以妥协:从今以后,他们只能用一只脚的大脚趾打字。(其余部分将用胶带封住。)

  33. 假定所有p{Math}代码点都是可见字符的代码是错误的。

  34. 假定w只包含字母、数字和下划线的代码是错误的。

  35. 假定^~是标点符号的代码是错误的。

  36. 假定ü具有元音的代码是错误的。

  37. 认为之类的内容包含任何字母的代码是错误的。

  38. 认为p{InLatin}p{Latin}相同的代码是严重损坏的。

  39. 认为p{InLatin}几乎永远有用的代码几乎肯定是错误的。

  40. 认为$FIRST_LETTER作为某些字母表中的第一个字母,而$LAST_LETTER作为该字母表中的最后一个字母,则[${FIRST_LETTER}-${LAST_LETTER}]几乎总是完全损坏、错误和没有意义的代码。

  41. 认为某人的名称只能包含某些字符的代码是愚蠢、无礼和错误的。

  42. 试图将Unicode简化为ASCII的代码不仅是错误的,而且它的肇事者永远不应该再被允许在编程中工作。句号。我甚至不确定是否应该允许他们再看一次,因为到目前为止,这显然没有给他们带来多大好处。

  43. 认为有某种方法可以假装文本文件编码不存在的代码是破碎和危险的。不妨把另一只眼睛也挖出来。

    /li>
  44. 将未知字符转换为?的代码是错误的、愚蠢的、愚蠢的,并且与标准建议相反,标准建议是:不要这样做!查看为什么不这样做。

  45. 认为自己可以可靠地猜测未标记文本文件的编码的代码犯下了致命的傲慢和幼稚混杂的错误,只有宙斯的闪电才能修复这些错误。

  46. 认为可以使用🐪printf宽度填充和调整unicode数据的代码是错误的。

  47. 代码认为,一旦您使用给定的名称成功创建了一个文件,当您在其包含的目录上运行lsreaddir时,您实际上会发现使用您创建该文件的名称的文件存在错误、损坏和错误。不要对此感到惊讶!

  48. 认为UTF-16是固定宽度编码的代码是愚蠢、错误的。吊销他们的编程许可证。

  49. 处理来自一个平面的代码点与处理来自任何其他平面的代码点略有不同的代码是本身损坏和错误的。回学校去。

  50. 认为/s/i之类的内容只能匹配"S""s"的代码是错误的。你会大吃一惊的

  51. 使用PMpM*而不是使用X查找字素簇的代码已损坏且错误。

  52. 应该全心全意地鼓励想要回到ASCII世界的人这样做,为了纪念他们的光荣升级,应该免费为他们提供一台前电动手动打字机,以满足他们所有的数据输入需求。发送给他们的信息应通过ᴀʟʟᴄᴀᴘs电报以每行40个字符的速度发送,并由信使手动递送。停止。

    /li>

😱𝕾𝖀𝕸𝕸𝕬𝕽𝖄😱


我不知道你能得到比我写的多多少"🐪中的默认unicode"。是的,我知道:您也应该使用Unicode::CollateUnicode::LineBreak。而且可能更多。

如您所见,有太多的Unicode内容需要执行才能让永远存在"默认为Unicode"这样的内容。

您将发现,就像我们在🐪5.8中所做的那样,不可能将所有这些事情强加给从一开始就没有正确设计以解决它们的代码。你善意的自私刚刚打破了整个世界。

即使这样做了,仍然有一些关键问题需要大量思考才能正确解决。没有你可以拨动的开关。只有大脑,我是说真正的大脑,在这里是足够的。你有很多东西需要学习。退回到手动打字机的模数,你根本不能指望在无知中偷偷溜走。这是21世纪的Unicode,你不能因为故意的无知而希望ˢᵗ消失。

你必须学会它。句号。"一切都正常"永远不会这么容易,因为这将保证许多事情不会起作用--这将使"让一切正常"的假设失效。

您可能能够为极少数和非常有限的操作获得一些合理的默认设置,但不能不比我想象的更多地考虑事情。

仅作为一个例子,规范排序将导致一些真正令人头疼的问题。😭、<2-141]、"ox{303}x{304}"‘ȭ’"ox{304}x{303}"‘ō̃’都应该匹配,但您究竟要如何做到这一点?这比看起来更难,但这是你需要考虑的事情。💣

如果说我对perl有什么了解的话,那就是它的UNICODE位能做什么、不能做什么,我向您保证:"̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲̲ɪ̲s̲̲ɴ̲ᴏ̲̲U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲̲ᴍ̲ᴀ̲ɢ̲ɪ̲ᴄ̲̲ʙ̲ᴜ̲ʟ̲ʟ̲ᴇ̲ᴛ̲̲"😞

您不能只更改一些默认设置就能一帆风顺。我确实是在PERL_UNICODE设置为"SA"的情况下运行🐪,但仅此而已,即使是这样,也主要是针对命令行内容。对于真正的工作,我经历了上面列出的所有步骤,而且我非常**非常**仔细地完成。


😈‘ƨdləɥƨᴉɥʇədoɥPuɐʻλɐpəɔᴉuɐəʌɐɥʻʞɔNL poo⅁😈

这篇关于为什么现代Perl在默认情况下避免使用UTF-8?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆