8

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

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

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

<2>参考资料说:

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

但是,当我查看引用的大小写折叠文件并阅读其中引用的UTR #21 “Case Mapping”时,我意识到大小写折叠被定义为与小写字母更相似的操作,而不是大写字母。套管。

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

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

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

4

2 回答 2

7

摘要:微软使用的措辞……至少可以说令人困惑。似乎应该完成简单的大写映射,但我不能确定。


背景

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

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

规格分析

(...)使用 Unicode 默认大小写转换算法、简单大小写转换变体(简单大小写折叠)转换为大写,并附上以下注释。<2> 比较每个大写的UTF-16 代码点二进制值。

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

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

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

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

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

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

例外清单

查看上述 Windows XP 和 Windows Server 2003 的例外列表,大多数条目都是减法,这表明 Microsoft 想要保持不同的代码点。但是,在表中,代码点实际上是按与 Unicode 大小写折叠数据文件相反的顺序列出的。

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

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

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

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

结论

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

  • 简单的大写映射
  • 简单大小写折叠,后跟简单大写映射
  • 简单的案例折叠

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

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

似乎唯一可以确定的方法是联系 Microsoft,或者煞费苦心地查看二进制文件以查看遵循哪种方法。

于 2013-11-28T21:43:01.790 回答
4

在Unicode 标准版本 6.2 – 核心规范的3.13 Default Case Algorithms (p. 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 以了解边界情况。

于 2013-11-27T21:08:26.520 回答