我目前正在研究 SBCS/DBCS 解码在 JDK 中的工作方式,并且我偶然发现了字符集实现中的一段奇怪的代码IBM930
(尽管它不是唯一的)。
首先,据我了解,JDK 实现者使用映射文件来生成大多数字符集类。例如:
IBM930.map
IBM930.nr non-roundtrip bytes override
IBM930.c2b non-roundtrip codepoints override
是DBCS实用程序解释生成的文件IBM930.java
。
如果我们仔细研究IBM930.nr
,就会发现:
25 000a
这意味着字节0x25
必须映射到\u000a
。
如果我们现在看一下IBM930.map
,我们会看到:
...
24 0084
25 000A <---
26 0017
...
因此,非往返覆盖已在主 .map 文件中指定。
如果我们打开IBM930.java
,可以在最底部看到:
static class EncodeHolder {
static final char[] c2b = new char[0x7400];
static final char[] c2bIndex = new char[0x100];
static {
String b2cNR = "\u0025\n";
String c2bNR = ...
DoubleByte.Encoder.initC2B(DecodeHolder.b2cStr, DecodeHolder.b2cSBStr,
b2cNR, c2bNR,
0x40, 0xfe,
c2b, c2bIndex);
}
}
具体来说,我指的是String b2cNR = "\u0025\n"
。
鉴于主 .map 文件已经包含 NR 覆盖,为什么生成过程仍然会生成非空值b2cNR
?
是不是因为并非所有 .map 文件都调整为包含 .nr 条目?
还是我忽略了该initC2B
方法的某个特定行为?
是的。
不,不是的。当然,问题不在于这些数据是如何被使用的。
相关类的源代码
sun.nio.cs.DoubleByte
可以在这里找到:https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/sun/nio/cs/DoubleByte.java。如果您跟踪通过DoubleByte.Encoder.initCB()
处理来自该文件的数据的操作b2cNR
,您会发现它并未用于定义从0x25
到的解码\u000a
。相反,它用于确保从文件到 的映射解码不0x25
用于定义从到 的编码。如果没有映射这样的解码,则该项目及其对应的条目将不起作用。\u000a
.map
\u000a
0x25
b2cNR
.nr
NR 数据不能很好地表征为覆盖。至少,它不是映射覆盖。相反,它们标记的是字节到字符(解码)方向的单向映射。因此,您可能会认为,重复完整的映射而不是仅提供字节是多余的,也许您是对的,但提供完整的映射可以提供一致性检查,并且如果存在编码为这些字节的不同字符,也许也更方便。
这是因为您误解了 .nr 条目的意义。.map 文件应该提供所有字节 <--> 字符的对应关系。.nr 条目将其中一些映射标记为单向。