使PHP脚本完全支持Unicode的声明

9

记住在 PHP 中完成所有与 Unicode 相关的工作以使其正常工作实在太棘手、繁琐且容易出错,因此我正在寻找一种方法,通过使用一个简单的声明,让 PHP 魔法般地将绝对可能的一切从古老的ASCII字节模式升级到现代Unicode字符模式

这个想法是为了使 PHP 脚本现代化,以便与 Unicode 一起使用,而不必在源代码中添加一堆令人困惑的替代函数调用和特殊的正则表达式。一切都应该只是“做正确的事情”,不需要问任何问题。

鉴于目标是最大程度地使用Unicode,最小限度地烦扰,这个声明必须至少执行以下操作(以及我忘记的任何其他有助于实现总体目标的操作):

  • PHP脚本源代码本身被认为是UTF-8编码的(例如,字符串和正则表达式)。

  • 所有输入和输出都会根据需要自动转换为/从UTF-8,并提供规范化选项(例如,将所有输入规范化为NFD并将所有输出规范化为NFC)。

  • 所有具有Unicode版本的函数都使用这些版本(例如,sortCollator::sort)。

  • 所有字节函数(例如,strlenstrstrstrpossubstr)的工作方式都像相应的字符函数(例如,mb_strlenmb_strstrmb_strposmb_substr)。

  • 所有正则表达式和正则表达式函数都透明地处理Unicode(即,像所有preggers隐含地附加了/u,以及像\w\b\s等东西都按照Unicode标准所要求的方式工作,等等)。

额外加分:),我希望有一种方法可以将此声明“升级”到完整的字形模式。这样,字节或字符函数就变成了字形函数(例如,grapheme_strlengrapheme_strstrgrapheme_strposgrapheme_substr),正则表达式也可以在正确的字形上工作(即,.——甚至[^abc]——匹配一个Unicode字形簇,无论它包含多少个代码点,等等)。

2个回答

6

“full-unicode” 是 PHP 6 的主要目标,但该版本已于一年前被取消。

所以,除了使用正确的函数并记住字符与字节不同之外,无法获得全部内容。


然而,对于您第四点可能有所帮助的是 mbstring 扩展的函数重载功能(引用):

mbstring 支持“函数重载”功能,可以通过在标准字符串函数上重载多字节替代品来添加多字节意识到此类应用程序,而无需进行代码修改。
例如,在启用函数重载时,将调用 mb_substr() 而不是 substr()


真的吗?它被取消了?为什么世界上会有人想要取消这么重要的事情,现在几乎整个网络都是Unicode了?:( - tchrist
如果还没有办法做到这一点(我本以为已经有了),那么我也接受一个解答,展示如何编写这样的代码。 - tchrist
如果有mbstring.func_overload,我觉得应该有一种方法使其适用于其他函数,包括grapheme_*。同样地,被弃用的mb_regex_set_options似乎正是所需的——只是它不包括/u用于preg_*。为什么这么麻烦呢?问题是PHP的模块/扩展机制不够丰富,无法使这些扩展自然而易于编写吗?你不能在某个表中添加一些东西吗,尤其是在第一个情况下?谢谢,Pascal。 - tchrist
糟糕,我想我已经找到了我模糊记忆中的东西。它是来自于这个提案的 unicode_semantics = On。我猜那从未发生过。他们真的最终在内部使用了令人讨厌的 UTF-16 吗?我希望不是:由于 ASCII 标记的密度,UTF-8 使得即使对于 CJK 来说,HTML 或 XML 更小。 - tchrist
UTF-16 是 PHP 6 中本应使用的编码方式。 - Pascal MARTIN
显示剩余3条评论

5
所有字节函数(例如strlen,strstr,strpos和substr)的工作方式都像相应的字符函数(例如mb_strlen,mb_strstr,mb_strpos和mb_substr)。
这不是一个好主意。
Unicode字符串无法透明地替换字节字符串。即使您正确处理所有可读文本为Unicode,仍然有重要用途的字节字符串在处理基于文件和网络数据,以及与显式使用字节的系统交互。
例如,输出一个标题‘Content-Length:’ .strlen($imageblob)并且如果突然使用码点语义,那么你就会得到一些问题。
您仍然需要同时具有mb_strlen和strlen,必须知道在每种情况下使用哪个才是正确的;没有单一的开关可以自动执行正确的操作。
这就是为什么我认为具有可以使用字节或码点语义进行处理的单个字符串数据类型的方法通常是一个错误。提供单独的字节字符串数据类型(具有字节语义)和字符字符串数据类型(具有Unicode码点语义(*))的语言更加一致。
(*:或UTF-16代码单元语义,如果不幸的话)

Perl似乎可以使用length来处理所有事情。有时您只需要将内部逻辑字符编码为UTF-8:print "Content-Length: ", length(utf8_encode($payload))。但这些情况很少见,因此使正常的strlen成为字节而不是字符是一种Huffman失败:短的东西应该是常见的东西。 - tchrist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接