特殊 ä ö 字符打破 UTF-8 编码

Posted

技术标签:

【中文标题】特殊 ä ö 字符打破 UTF-8 编码【英文标题】:Special ä ö characters break UTF-8 encoding 【发布时间】:2019-07-22 10:21:39 【问题描述】:

我网站上的用户在文本字段中输入了特殊字符:ä ö

这些显然与我可以从键盘输入的 ä ö 字符不同,因为当我将它们粘贴到程序员的记事本中时,它们分成了两个:a¨ o¨

在我网站的服务器端,我有一个 php 脚本,它可以识别用户输入中的非法特殊字符,并在带有 preg_replacehtml 错误消息中突出显示它们。

字符拆分也发生在那里,所以我得到一个正常的字母 a 和 o,带有一个奇怪的单独 xCC 字符,它破坏了 UTF-8 字符串编码,json_encode 函数因此失败。

处理这些字符的最佳方法是什么?我应该尝试替换特殊的 ä ö 字符并用常规字符替换它们,还是我可以以某种方式捕获损坏的 UTF-8 字符并删除或替换它们?

【问题讨论】:

听起来您的脚本可能一直没有设置为 UTF8,请查看 a previous answer of mine 和 UTF-8 all the way through。 @Qirel 我认为这里的编码没有任何问题;复制和粘贴它们的行为表明它们是有效的组合变音符号,脚本只是没想到这些。 @deceze 我不相信that question 是一个合适的副本。两者都是关于规范化的,但是一个需要 ASCII,这个很乐意使用 UTF-8。 【参考方案1】:

并不是这些字符破坏了编码,只是Unicode真的很复杂

常用的重音字母在 Unicode 标准中有自己的码位,在这种情况下:

U+00E4 "带分音符号的拉丁小写字母 A" U+00F6 "带分音符号的拉丁小写字母 O"

但是,为了避免对所有可能性进行编码,特别是当需要在同一个字母上放置多个变音符号(重音符号)时,Unicode 包含“组合变音符号”,例如:

U+0308 "结合分音符"

当放置在普通字母的代码点之后时,这些代码点在显示时为其添加变音符号

如您所见,这意味着有两种不同的方式来表示同一个字母。为了解决这个问题,Unicode 包含“规范化形式”defined in an annex to the Unicode standard:

规范化表格 D (NFD):规范分解 规范化表格 C (NFC):规范分解,然后是规范组合 标准化形式 KD (NFKD):兼容性分解 规范化形式 KC (NFKC):兼容性分解,然后是规范组合

暂时忽略“兼容性”表单,我们有两种选择:

分解,尽可能频繁地使用组合变音符号 组合,尽可能频繁地使用特定代码点

因此,一种可能性是将您的输入转换为 NFC,这在 PHP 中可以通过 the Normalizer class in the intl extension 实现。

但是,并非所有组合都可以规范化为没有单独变音符号的形式,因此这并不能解决您的所有问题。您还需要查看您想要允许的确切字符,可能是matching Unicode character properties。

您可能还想了解“字素集群”并使用the relevant PHP functions。 “字素簇”,或者只是“字素”,是大多数读者认为的“一个字符”——例如。带有所有变音符号的字母或完整的表意文字。

【讨论】:

Normalizer 类确实解决了字符问题。感谢您的回答,内容非常丰富。我将不得不进一步研究此事并调整我的解决方案。

以上是关于特殊 ä ö 字符打破 UTF-8 编码的主要内容,如果未能解决你的问题,请参考以下文章

带有 åäö(特殊字符)的 Alamofire GET 请求,无效 url

WCF 服务因特殊字符而失败

字符 Å Ä Ö 没有显示在我的 DDL 中,我如何告诉 restclient 使用特定的字符集?

用于用户名验证的正则表达式

如何从文件中读取特殊字符?

从 Android 应用程序调用 PHP REST API 无法正确显示变音符号 (äüö)