【发布时间】:2019-06-13 02:01:15
【问题描述】:
我有一个在 Perl 中处理 XML 编码的遗留应用程序,最有可能是 UTF-8,它需要将该 XML 的一些数据存储在某个数据库中,由于历史原因,该数据库使用 windows-1252。是的,这个设置不能支持 Unicode 标准的所有可能字符,但实际上我不需要,并且可以尝试合理兼容。
目前的具体问题是一个包含LATIN SMALL LETTER U, COMBINING DIAERESIS(U+0075 U+0308)的文件,这使得Perl将Unicode字符串的现有编码打破为windows-1252,但以下异常:
"\x{0308}" 不映射到 cp1252
我能够使用Unicode::Normalize::NFKC 解决这个问题,它创建了字符U+00FC (ü),它完美地映射到windows-1252。这当然会导致其他一些问题,例如如果是字符 VULGAR FRACTION ONE HALF (½, U+00BD),因为 NFKC 会为此创建 DIGIT ONE, FRACTION SLASH, DIGIT TWO (1/2, U+0031 U+2044 U+0032),然后 Perl 又会死掉:
"\x{2044}" 不映射到 cp1252
根据normalization rules 的说法,这对于NFKC 来说非常好。我使用它是因为我认为它会给我最兼容的结果,但那是错误的。改用NFC 解决了这两个问题,因为在这种情况下,这两个字符都提供了与windows-1252 兼容的normalization。
这种方法对于通常可以使用与windows-1252 兼容的规范化的字符(仅与NFC 不同)会带来额外的问题。一个例子是LATIN SMALL LIGATURE FI (fi, U+FB01)。根据它的normalization rules,NFC之后的表示与windows-1252不兼容,而这次使用NFKC导致两个字符与windows-1252兼容:fi(U+0066 U+0069)。
我目前的方法是简单地尝试编码为windows-1252,如果失败我使用NFC,然后再试一次,如果失败我使用NFKC,然后再试一次,如果失败我我现在要放弃了。这适用于我目前正在处理的情况,但如果我上面示例的所有三个字符同时出现在字符串中,显然会失败。无论NFC 和NFKC 的顺序如何,总会有一个字符导致windows-1252-incompatible 输出。唯一的问题是哪个字符何时中断。
但重要的一点是每个字符本身都可以规范化为与windows-1252 兼容的东西。似乎没有一劳永逸的解决方案。
那么,我是否缺少一些已经以最向后兼容的方式进行转换的 API?
如果不是,我需要自己实现什么方法来支持一个字符串中的所有上述字符?
听起来我需要按 Unicode 字符处理每个字符串 Unicode 字符,使用与 windows-1252 最兼容的内容单独标准化,然后再次连接结果。是否有一些可用的增量 Unicode 字符解析器可以处理字符和内容的组合?一个简单的基于 Unicode 字符的正则表达式是否已经处理了这个问题?
Unicode::Normalize 提供了额外的功能来处理partial strings 等,但我必须承认我目前并不完全理解它们的目的。这些示例也关注连接,但据我了解,我首先需要一些解析才能以不同方式规范化各个字符。
【问题讨论】:
-
在整个字符串(我认为是单词)的转换失败的情况下,您可以按字符进行吗?它确实正确读取了 utf-8(对吗?),所以你有字符。也许不漂亮,但它应该照顾它?
-
在正确处理字符和内容的组合时,您对将某些字符串拆分为单独的 Unicode 字符有何建议?我目前对那部分有点不确定。
-
由于您似乎已经控制了转换(到 cp-1252 编码)本身,我假设它是关于识别用于转换的“字符”,以及所有 Unicode 标记等等。那将是正则表达式中的
\X,它匹配逻辑字符(作为单个或多个代码点)。