perl - 为什么默认情况下现代Perl避免UTF-8?

  显示原文与译文双语对照的内容

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

我理解核心Perl脚本存在许多遗留问题,它可能会破坏。 但是,从我的角度看,在 21 st 世纪,大的新项目( 或者具有大视角的项目) 应该从零开始。 仍然没有看到发生。 例如 Moose 支持严格和警告,但不支持 Unicode 。Modern::Perl 也减少了样板,但没有UTF-8处理。

为什么有一些原因还有UTF-8在现代Perl项目在年 2011?


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

似乎我没有明确自己。 让我尝试添加一些东西。

tchrist,我看到情况相当相似,但我们的结论完全相反。 我同意,统一码的搜索问题是复杂的,但是这就是为什么我们( Perl用户和程序员) 需要一些层( 或者杂注) 这使得UTF-8处理一样简单,因为它必须是如今。

于几天甚至weeks,相关 tchrist 尖那么多的方面可以用来的事我是阅读和思考。 但这并不是我的观点。 tchrist 试图证明没有,不存在单"启用 utf-8"方式。 我没有那么多的知识来争论。 所以我坚持使用活生生的例子。

我使用了 Rakudo 和 UTF-8,因为我需要的是 我没有问题,它只是工作。 也许在更深层的地方有一些限制,但是在开始时,我所测试的一切都像我预期的那样工作。

这是不是现代 Perl 5的目标? 应力之更我,我马上不打算推荐以核心 Perl,我建议可能对它的触发的默认字符集 UTF-8 啪地一声对于那些开发项目。

另一个例子,但音调更负。 框架应该使开发更加容易。 几年前,我尝试了web框架,但是只是把它们扔掉,因为"启用 UTF-8"太晦涩了。 我没有找到如何和在哪里挂接Unicode支持。 它太长了,我发现走旧的老路很容易。 现在我看到这里有一个奖励,可以处理与 Mason 2相同的问题: 如何使 Mason2 utf8干净? ,所以它是非常新的框架,但是使用它与UTF-8需要深入了解它的内部。 就像一个大大的红色标志: 停止,不要使用我 !

我很喜欢 Perl,但处理Unicode很痛苦。 我仍然在墙壁上奔跑。 某种方式 tchrist 是作对了,回答我的问题 新项目不吸引 UTF-8,因为它在 Perl 5中太复杂。

时间:


处理Unicode文本有两个阶段。 第一个是"如何输入并输出而不丢失信息"。 第二个是"如何根据本地语言约定处理文本"。 tchrist的文章涵盖了两者,但第二部分是他文章中的99%篇文章。 大多数程序甚至不正确地处理 IO,所以在你开始担心规范化和排序之前,理解它是很重要的。

这篇文章旨在解决第一个问题

当你将数据读入Perl时,它不关心它是什么编码。 它分配一些内存并将字节存储在那里。 如果你说 print $str,它只是blits这些输出到终端,这可能是设置为假设的所有内容都将写入字节数据 UTF-8,以及你的文字自己来了

精彩。

但不是这样的。如果你试图把数据当作文本对待,你会发现发生了一些坏事。 你需要更进一步才能看到Perl对你的字符串和你对字符串的看法是什么。 写一个one-liner像: perl -E 'while(<>){ chomp say length }' 输入 文字化け 并得到 12.。 不是正确的答案,4.

这是因为Perl假设你的字符串不是文本。 你必须告诉它它是文本,它给你正确的答案。

这很简单;编码模块有这样的功能。 一般入口点是 Encode::decode ( 或者 use Encode qw(decode),当然) 。 函数接受来自外部世界( 我们要调用的内容"八位字节的一些字符串"这是一种saying的方式"位字节"),并将它的转换成一些Perl将理解的文本。 第一个参数是字符编码名称,如"utf-8"或者"ascii"或者"euc-jp"。 第二个参数是字符串。 返回值是包含文本的Perl标量。

( 还有 Encode::decode_utf8,它假定编码为 UTF-8.)

如果重写 one-liner:


perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'

我们输入文字化け并获取" 4"作为结果。 成功。

这就是在Perl中解决 99%个Unicode问题的解决方案。

关键是,当任何文本进入你的程序时,你必须解码它。 互联网无法传输字符。 文件无法存储字符。数据库中没有字符。 只有八位字符,你不能将八位字节视为Perl中的字符。 必须使用编码模块将编码的八位字节解码为Perl字符。

问题的另一半是从程序中获取数据。 这很容易;你只需说 use Encode qw(encode),决定数据在( 在 Windows,UTF-8到终端可以理解 UTF-8,UTF-16用于文件) 中的编码,然后输出 encode( $encoding, $data ) 而不是输出 $data

这里操作将perl的字符转换为你的程序操作的字符,它可以被外部世界使用。 如果我们可以通过互联网或者终端发送字符,这将变得简单很多,但我们不能: 只有八进制字符。所以我们必须将字符转换成八位字节,否则结果是未定义的。

总结:编码所有输出,解码所有输入。

现在我们将讨论三个问题,使这些问题成为一个小挑战。 第一个是库。它们是否正确处理文本? 答案是。。他们尝试。 如果你下载网页,LWP将把你的结果作为文本返回。 在你的数据库对分析结果。., 如果调用正确的方法,这就是( 这正好是 decoded_content,而不是 content,它只是来自服务器的八进制流。) 数据库驱动程序可以是片状;如果使用 DBD::SQLite,只不过 Perl,问题都会解决,但是如果一些其他工具已经设置文本存储为某种编码以外 除非你编写代码正确处理它,否则它不会被正确处理。

输出数据通常比较容易,但是如果你看到"打印中的宽字符",那么你就会知道在某处搞乱了编码。 那个警告意味着"嘿,你试图把Perl字符泄露到外部世界,但这并没有意义"。 你的程序似乎工作于( 因为另一端通常处理原始Perl字符),但它非常中断,随时可以停止工作。 用显式的Encode::encode 修复它 !

第二个问题是UTF-8编码源代码。 除非你在每个文件的顶部说 use utf8,否则Perl不会认为你的源代码是 UTF-8. 这意味着每次你说类似 my $var ='ほげ'的东西,你都会把垃圾注入到你的程序中,这会彻底破坏一切。 你不必在你的program,"使用 utf8",但如果不这样做,你必须不使用任何 non-ASCII characters.

第三个问题是Perl如何处理过去。 很久以前,没有像Unicode这样的东西,perl假设一切都是Latin-1文本或者二进制。 所以当数据进入你的程序,你开始把它当作文本对待时,Perl将每个八位字节当作一个Latin-1字符对待。 这就是为什么当我们要求"文字化け"的长度时,我们得到了 12.

这叫做"隐式升级",它是一个完全合理的事情,但如果你的文本不是 Latin-1,它不是你想要的。 这就是显式解码输入的关键: 如果你不这么做,Perl会做,它可能会出错。

当一半的数据是一个正确的字符串,还有一些仍然是二进制时,人们会遇到麻烦。 Perl将把仍然是二进制的部分解释为Latin-1文本,然后将它的与正确的字符数据组合。 这将使它看起来像处理你的字符正确地破坏了你的程序,但实际上你只是没有解决问题。

下面是一个示例:你有一个读取UTF-8-encoded文本文件的程序,你将一个 Unicode PILE OF POO 粘贴到每行,然后打印出来。 这样写:

 
  
( <> ) { chomp ;说"$ _   
 

我们都同意这是一个很困难的问题,但这恰恰是试图让所有人都更加容易的原因。

在CPAN上有一个最近的模块: utf8::all 尝试"打开 Unicode"。 所有的of 。

半导体,作为已经( 外部程序,外部站点请求等) 指出,你不能神奇地让整个系统使用统一码常见问题,但正是我们可以一起工作,以作出明智的工具使更加容易。 这就是为什么我们是程序员。

如果 utf8::all 不做你认为应该做的事情,让我们改进它,让它更好。 或者让我们做一些能够满足不同人需求的额外工具。

我认为你误解了Unicode及其与Perl的关系。 无论你存储数据,Unicode,ISO-8859-1 或者其他的东西,你的程序都必须知道如何解释作为输入( 解码)的字节,以及如何表示它想要输出的信息。 得到解释错误,你搞乱了数据。 你的程序中没有一些神奇的默认设置,它将告诉程序外部的东西如何操作。

你觉得很困难,很可能是因为你习惯了所有的东西。 你应该考虑的一切都被编程语言忽略,所有它必须与之交互的东西。 如果所有东西都没有使用 UTF-8,你没有任何选择,那么UTF-8就像简单的一样。 但并非所有的都使用 UTF-8. 在会议上可以处理例如你不希望你的输入句柄会认为它是越来越UTF-8八位组,除非它们实际上代表,并且你不希望让输出处理成UTF-8如果东西 reading. Perl无法知道那些东西。 这就是为什么你是程序员。

我不认为 Perl 5中的Unicode太复杂了。 我觉得这很可怕,人们避免了它。 有一个区别。为此,我将Unicode放在 学习 Perl,6版 还有很多Unicode的东西 有效的Perl编程 你必须花时间学习和理解Unicode以及它的工作原理。 否则,你将无法有效地使用它。

在阅读这个帖子时,我经常会觉得人们在使用"utf-8"作为"unicode"的同义词。 请区分"unicode的code-points",它是ASCII代码和各种 unicode"编码"的放大相对。 其中一些是 UTF-8,UTF-16和UTF-32是当前的,还有一些是过时的。

请注意,UTF-8 ( 以及其他所有编码编码) 存在并且在输入或者输出中有意义。 在内部,由于 Perl 5.8.1,所有字符串都保留为 Unicode"code-points"。 真的,你必须启用上面的一些功能。

Meir

古代的数量也是一个真正horrifying代码出街,大部分对它作成常见的CPAN模块。 在几个我使用Perl脚本定期我发现我有很要小心启用Unicode如果我使用外部模块,这些模块可能会受到移动它,现在仍然在试图确定和修复一些 Unicode-related failures.

...