【问题标题】:Unicode case folding to upper caseUnicode 大小写折叠为大写
【发布时间】:2013-11-24 21:52:14
【问题描述】:

我正在尝试根据该格式的官方规范实现一个用于读取 Microsoft CFB(复合文件二进制)格式文件的库。规范可用from this site

简而言之-文件的某些结构存储在红黑树中。我对用于在该树中存储这些结构的比较谓词有疑问。规范说,如果这些结构的名称(字符串存储为 UTF-16,Windows API 中的标准)不同,则有必要遍历每个 UTF-16 代码点并且:

(...) 使用 Unicode 默认大小写转换转换为 大写 算法,简单大小写转换变体(简单大小写折叠),带有以下注释。 比较每个大写的 UTF-16 码位二进制值。

<2> 参考说:

或 Windows XP 和 Windows Server 2003:复合文件实现 符合 Unicode 3.0.1 默认大小写转换算法,简单大小写折叠 (http://www.unicode.org/Public/3.1-Update1/CaseFolding-4.txt),但有以下例外。

但是,当我查看引用的 case fold 文件并阅读其中引用的 UTR #21 "Case Mapping" 时,我意识到 case fold 被定义为更类似于小写而不是大写的操作.

通过CaseFolding-4.txt,我们可以得到大写字母到小写字母的大小写折叠映射。映射始终为 1 对 1,因为此处不需要完全折叠(扩展为多个字符的那些)。然而,小写字母到大写字母的反向映射不再那么简单了。例如,

0392; C; 03B2; # GREEK CAPITAL LETTER BETA
03D0; C; 03B2; # GREEK BETA SYMBOL

因此,我们无法知道应该将03B2 转换为0392 还是03D0。标准是否定义了像折叠成大写这样的东西?也许我应该使用大小写折叠,然后转换为大写?还是我对规范的理解完全错误?

【问题讨论】:

  • 大小写折叠只是一种标准化以忽略大小写的方法。是大写还是小写都无所谓。

标签: unicode utf-16 case-folding


【解决方案1】:

总结: Microsoft 使用的措辞...至少可以说令人困惑。看来应该做简单的大写映射,虽然我不能确定。


背景

部分混淆可能是案例折叠案例映射之间的区别。大小写映射将每个字符映射到指定的大小写。大小写折叠虽然基于小写,但被定义为产生 case-less 字符 (UTR #21 §1.3)。

现在有两种情况映射和情况折叠的变体,simplefull。与简单的转换不同,完整的转换可以更改字符串长度,正如您正确指出的那样,这里不需要。该规范特别提到了简单,并且可能是这个答案中唯一明确的事情。我确实觉得有必要提及当前的 Unicode 标准 (6.3.0) 提到 default 大小写转换是完整的,尽管 Microsoft 引用的版本 (3.1.1) 确实如此似乎没有做出这种区分。

规格分析

(...) 使用 Unicode 默认大小写转换算法转换为 大写,简单大小写转换变体(简单大小写折叠),并带有以下注释。 比较每个 大写 UTF-16 码位二进制值。

对我来说,这句话似乎暗示他们想要大写,只是通过说大小写折叠而不是大小写映射而犯了一个错误。但是随后出现了您引用的参考:

对于 Windows XP 和 Windows Server 2003:复合文件实现符合 Unicode 3.0.1 默认大小写转换算法,简单大小写折叠 (http://www.unicode.org/Public/3.1-Update1/CaseFolding-4.txt),但有以下例外。

他们实际上提到了案例折叠数据文件!在这一点上,我不知道该怎么想。我的主要思路是微软希望折叠外壳,尽管错误地认为它是基于上壳而不是下壳。虽然这有点牵强,但它是我能够调和这种可能矛盾的最接近的方法,我希望有更好的解释。

我在section 2.6.1 中发现以下支持某种形式的大写:

[...] 目录条目名称使用不区分大小写的特殊大写映射进行比较,如Red-Black Tree 中所述。

请注意,他们实际上在这里使用了术语映射

例外列表

查看上面提到的 Windows XP 和 Windows Server 2003 的 exception list,大多数条目都是减法,表明 Microsoft 希望保持不同的代码点。但是,在表中,代码点实际上是按与 Unicode 大小写折叠数据文件相反的顺序列出的。

对此的一种解释是,它只是一个显示怪癖。这个想法被他们减去案例转换0x03C2 -> 0x03C2的最后一行击落了。该转换在数据文件中不存在,因为转换 0x03C2 -> 0x03C3 存在(未列出的案例转换被视为转换为自身)。

另一种解释是,他们实际上错误地认为它的反向映射是正确的映射。正如您所提到的,这会遇到麻烦,因为反向映射并不总是那么简单。否则,这个解释就好了。

第三种解释是认为他们对 Unicode 大小写折叠数据文件的引用是错误的。这当然让我感到不安,但如果他们最初确实意味着案例映射,他们可能只是提供了链接作为快速参考点。他们提到的例外列表确实有列标题,例如“小写 UTF-16 代码点”,但我们知道大小写折叠实际上是无大小写的。

顺便说一句,我确实查看了后来的操作系统的例外列表,希望获得更多的见解。我发现更多的困惑。特别是添加0x03C3 -> 0x03A3 让我很困扰。由于异常列表和 Unicode 文件以相反的顺序列出了它们的代码点,看来转换已经在数据文件中,不需要添加。这部分规范不想看懂!

结论

如果您已阅读以上所有内容,您可能会猜到这个结论会不太理想。很明显,在一个或多个点上,规范是错误的,但很难说在哪里。确实有三种可能性,具体取决于您对需要进行哪种案例转换的解释。

  • 简单的大写映射
  • 简单的大小写折叠,然后是简单的大写映射
  • 简单的外壳折叠

在我看来,微软确实想要大写字母。从那里我相信案例折叠参考是一个错误,因此我的猜测是他们只想要简单的大写映射。

我非常怀疑这是最后一个简单的案例折叠唯一选项。其他两个选项都会给出非常相似的结果,只有少量代码点可能会给出不同的结果。

似乎唯一可以确定的方法是联系 Microsoft,或者仔细查看二进制文件以了解遵循哪种方法。

【讨论】:

  • 非常感谢您提供如此详尽的回答。如我所料,如果我要做到 100% 正确,唯一的选择就是联系 Microsoft。
【解决方案2】:

The Unicode Standard Version 6.2 – Core Specification 的 3.13 默认案例算法(第 115 页)中,文本指的是UnicodeData.txt。这包含:

03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392
03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392

这表明 希腊小写字母 Beta 确实应该映射到 希腊 Beta 符号,并且顺便表示这两个符号具有一定程度的兼容性。它还包含您正在寻找的双向大小写转换的其余部分。您可能还需要查看 SpecialCasing.txt 以了解边界情况。

【讨论】:

  • 你不能看看unicode.org/Public/UNIDATA/CaseFolding.txt吗?它似乎涵盖了所有简单的案例折叠。
  • @bzlm 如OP中所述,这仅提供小写字符方向的转换,并且算法比较大写字符串。结果可能相似,但如示例所示,转换是多对一的,因此不可逆。
猜你喜欢
  • 2019-07-03
  • 2014-07-08
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 2011-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多