现代Perl为什么要避免使用UTF
我想知道为什么使用Perl构建的大多数现代解决方案默认情况下都不启用UTF-8。
我明白核心Perl脚本存在许多遗留问题,它可能会破坏一些东西。 但是,从我的观点来看,在21世纪,大型新项目(或者具有较大观点的项目)应该从头开始对其软件进行UTF-8验证。 我仍然没有看到它发生。 例如,穆斯启用严格和警告,但不是Unicode。 Modern :: Perl也减少了样板,但没有UTF-8处理。
为什么? 在2011年的现代Perl项目中是否有避免使用UTF-8的原因?
评论@ tchrist时间太长,所以我在这里添加它。
我似乎没有说清楚。 让我试着添加一些东西。
特里斯特和我看到的情况非常相似,但我们的结论完全是相反的。 我同意,Unicode的情况很复杂,但这就是为什么我们(Perl用户和编码人员)需要一些使UTF-8处理像现在一样容易的层(或杂注)。
Tchrist指出要涵盖很多方面,我会在几天甚至几周内阅读并思考它们。 不过,这不是我的观点。 tchrist试图证明没有一种方法“启用UTF-8”。 我没有那么多的知识来解决这个问题。 所以,我坚持活着的例子。
我玩Rakudo,UTF-8就在我需要的地方 。 我没有任何问题,它只是工作。 也许在更深的地方有一些限制,但在开始时,我测试的所有产品都按我的预期工作。
这不应该成为现代Perl 5的一个目标吗? 我更强调的是:我不建议UTF-8作为Perl核心的默认字符集,我建议为那些谁开发新项目能够轻松地触发它的可能性。
另一个例子,但有一个更负面的基调。 框架应该使开发更容易。 几年前,我尝试了Web框架,但是把它们扔掉了,因为“启用UTF-8”是如此晦涩难懂。 我没有找到如何以及在何处挂钩Unicode支持。 这很耗时,我发现它很容易走旧路。 现在我在这里看到了与Mason 2相同的问题:如何让Mason2 UTF-8变得干净? 所以,这是一个非常新的框架,但是使用它与UTF-8需要深入的内部知识。 它就像一个巨大的红色标志:停下来,不要使用我!
我真的很喜欢Perl。 但处理Unicode是痛苦的。 我仍然发现自己跑在墙上。 有些方法tchrist是正确的,它回答了我的问题:新项目不吸引UTF-8,因为它在Perl 5中太复杂了。
处理Unicode文本有两个阶段。 首先是“我怎样才能输入并输出它而不会丢失信息”。 第二个是“如何根据当地语言惯例来对待文本”。
崔克里斯特的帖子涵盖了两者,但第二部分是他帖子中99%的文字来自哪里。 大多数程序甚至不能正确处理I / O,因此在您开始担心规范化和整理之前,了解这一点很重要。
这篇文章旨在解决第一个问题
当你将数据读入Perl时,它并不关心它是什么编码。 它分配一些内存并在那里存储字节。 如果你说print $str
,它会将这些字节输出到你的终端,这可能是假设所有写入它的内容都是UTF-8,并且你的文本显示出来。
奇妙。
除了,它不是。 如果您试图将数据作为文本处理,您会看到“正在发生错误”。 你需要去没有比length
一看就知道是什么的Perl想着你的字符串,你怎么看待您的字符串不同意。 写一个类似于: perl -E 'while(<>){ chomp; say length }'
perl -E 'while(<>){ chomp; say length }'
并键入文字化け
,你会得到12 ...不是正确的答案,4。
这是因为Perl假设你的字符串不是文本。 你必须告诉它,它是文本,才能给你正确的答案。
这很简单, 编码模块具有这样的功能。 通用入口点是Encode::decode
(或者use Encode qw(decode)
,当然)。 这个函数需要一些来自外部世界的字符串(我们称之为“八位字节”,一种说“8位字节”的方式),并将它转换成Perl可以理解的一些文本。 第一个参数是一个字符编码名称,如“UTF-8”或“ASCII”或“EUC-JP”。 第二个参数是字符串。 返回值是包含文本的Perl标量。
(还有Encode::decode_utf8
,它使用UTF-8编码。)
如果我们重写我们的单行版本:
perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'
我们输入文字化け,并得到“4”。 成功。
那就在这里,解决了Perl中99%的Unicode问题。
关键是,每当任何文本进入你的程序,你必须解码它。 互联网不能传输字符。 文件不能存储字符。 数据库中没有字符。 只有八位字节,并且不能将八位字节视为Perl中的字符。 您必须使用Encode模块将编码的八位组解码为Perl字符。
问题的另一半是从您的程序中获取数据。 这很容易; 您只需use Encode qw(encode)
,决定数据的编码方式(UTF-8与理解UTF-8的终端,Windows上的文件的UTF-16等),然后输出encode($encoding, $data)
结果encode($encoding, $data)
而不是只输出$data
。
该操作将Perl的字符(这是您的程序运行的内容)转换为外部世界可以使用的八位字节。 如果我们只能通过互联网或我们的终端发送字符,那将会容易得多,但我们不能:只有八位字节。 所以我们必须将字符转换为八位字节,否则结果是不确定的。
总结一下:编码所有输出并解码所有输入。
现在我们将讨论三个问题,这使得这有点具有挑战性。 首先是图书馆。 他们是否正确处理文本? 答案是......他们尝试。 如果你下载了一个网页,LWP会以文本形式返回你的结果。 如果你对结果调用正确的方法,那就是(并且恰好是decoded_content
,而不是content
,它只是它从服务器获得的八位字节流)。数据库驱动程序可以是片状的; 如果只使用DBD :: SQLite,那么它就会运行,但如果其他工具已经将数据作为UTF-8以外的其他编码存储在数据库中,那么......它不会被正确处理直到你编写正确处理它的代码。
输出数据通常比较容易,但是如果您看到“打印中的宽字符”,那么您知道您正在搞乱编码。 这个警告的意思是“嘿,你试图把Perl的角色泄露给外部世界,这没有任何意义”。 你的程序似乎可以正常工作(因为另一端通常会正确处理原始的Perl字符),但它很破碎,随时都可能停止工作。 用明确的Encode::encode
修复它!
第二个问题是UTF-8编码的源代码。 除非你说在每个文件的顶部use utf8
,Perl不会认为你的源代码是UTF-8。 这意味着每当你说出像my $var = 'ほげ'
这样的东西时,你就会向你的程序中注入垃圾,这将彻底破坏所有的东西。 您不必“使用utf8”,但如果您不使用,则不得在程序中使用任何非ASCII字符。
第三个问题是Perl如何处理过去。 很久以前,没有Unicode这样的东西,Perl认为一切都是Latin-1文本或二进制文件。 所以当数据进入你的程序并开始把它当作文本处理时,Perl将每个八位字节视为一个拉丁-1字符。 这就是为什么当我们询问“文字化け”的长度时,我们得到了12个.P Perl认为我们正在使用Latin-1字符串“æååã”(这是12个字符,其中一些是非打印的)。
这被称为“隐式升级”,这是一个完全合理的做法,但如果您的文本不是Latin-1,则不是您想要的。 这就是为什么明确解码输入至关重要:如果你不这样做,Perl会做,而且它可能会做错。
人们遇到麻烦,其中一半的数据是适当的字符串,而另一些仍然是二进制的。 Perl会将仍然是二进制文件的部分解释为Latin-1文本,然后将其与正确的字符数据组合。 这会让你看起来像处理你的角色正确地破坏了你的程序,但实际上,你只是没有把它修好就够了。
下面是一个例子:你有一个程序读取一个UTF-8编码的文本文件,然后在每一行上PILE OF POO
一个PILE OF POO
,然后打印出来。 你这样写:
while(<>){
chomp;
say "$_
链接地址: http://www.djcxy.com/p/59217.html