本文目录导读:

这是一个关于 Java Swing 中 JEditorPane、HTMLEditorKit 以及 HTML 解析器对八进制(Octal)编码处理的技术问题。
在标准的 HTMLEditorKit / Parser 中,对于数字字符引用(Numeric Character Reference),它通常只支持十进制(如 A)和十六进制(如 A),而不支持八进制(如 e,但注意 e 实际上是十进制 101,不是八进制 101 对应的十进制 65)。
我们需要先澄清一个重要的概念混淆,然后再说实现。
核心概念:HTML 字符引用中的进制
在 HTML 或 XML 中,数字字符引用(NCR)只有两种标准写法:
- 十进制:
&#d;—— 其中的d是十进制数字。 - 十六进制:
&#xh;或&#Xh;——h是十六进制数字。
HTML 标准从来就不支持八进制。
当你看到 e,解析器(包括 HTMLEditorKit.Parser)会按照十进制 101 来解释,它对应的是字符 e,而不是八进制 101(十进制 65,即 A)。
HTMLEditorKit.Parser 的实际行为
javax.swing.text.html.HTMLEditorKit.Parser 是一个抽象类,它依赖于具体的实现(通常是 javax.swing.text.html.parser.ParserDelegator)来解析 HTML。ParserDelegator 内部使用了一个 DocumentParser,它严格遵循 HTML 规范,仅处理十进制和以 0x 或 0X 开头的十六进制值。
测试示例(证明不支持八进制):
import javax.swing.*;
import javax.swing.text.html.*;
import java.io.StringReader;
public class OctalTest {
public static void main(String[] args) throws Exception {
JEditorPane pane = new JEditorPane();
pane.setEditorKit(new HTMLEditorKit());
// 情况1:标准十进制 65 -> 'A'
String htmlDec = "<html><body>A</body></html>";
pane.read(new StringReader(htmlDec), "text/html");
SwingUtilities.invokeLater(() -> System.out.println("Decimal 65: " + pane.getText()));
// 情况2:如果误以为 e 是八进制(对应十进制65),实际解析为十进制101 -> 'e'
String htmlMis = "<html><body>e</body></html>";
pane.read(new StringReader(htmlMis), "text/html");
SwingUtilities.invokeLater(() -> System.out.println("Numeric 101: " + pane.getText()));
// 情况3:官方不支持八进制,e 会被解析为什么?
// 由于0开头,一些解析器可能将0101解释为十进制101(忽略前导零),或者报错。
// Swing的实现会将其作为十进制101处理(前导零被忽略)
String htmlLeadZero = "<html><body>e</body></html>";
pane.read(new StringReader(htmlLeadZero), "text/html");
SwingUtilities.invokeLater(() -> System.out.println("With leading zero 0101: " + pane.getText()));
}
}
结果:
A→ 显示Ae→ 显示e(不是八进制处理后的A)e→ 显示e(前导零被忽略,当作十进制 101)
为什么有人会问“八进制处理”?
可能是因为在 其他语言或旧版解析器 中,有些(非标准)实现会将带有前导零的数字(如 e)当作八进制来处理。
- 在 C/C++ 中,
0101是八进制,等于十进制 65。 - 在 JavaScript 的旧版
String.fromCharCode()中,'\101'是八进制。
但在 Java 的 HTML 解析器 中,不会这样处理。
如果你确实需要支持自定义的“八进制” NCR
如果由于某些历史原因,你需要让 JEditorPane 支持将 e 等视为八进制,你必须重写解析逻辑,方法如下:
方案:自定义 HTMLEditorKit + ViewFactory
- 继承
HTMLEditorKit,重写getViewFactory(),返回一个自定义的ViewFactory。 - 自定义
HTMLDocument或使用HTMLReader的回调处理自定义实体。 - 正则替换(简单但有限):在将 HTML 字符串设置给
JEditorPane之前,手动将�[0-7]+;匹配的内容转换为对应的十进制 Unicode。
// 示例:将 �xxx 视为八进制
String html = "e"; // 八进制101 -> 十进制65 -> 'A'
String processed = html.replaceAll("�([0-7]+);", match -> {
String octalDigits = match.group(1);
int charCode = Integer.parseInt(octalDigits, 8); // 八进制转十进制
return "&#" + charCode + ";";
});
// processed = "A"
然后将 processed 交给 pane.read(...) 或 pane.setText(processed)。
| 问法 | 实际含义 | HTMLEditorKit 行为 |
|---|---|---|
A |
十进制 65 | 正确解析为 A |
A |
十六进制 41 | 正确解析为 A |
e |
十进制 101 | 解析为 e(不是八进制) |
e |
带前导零的十进制 | 解析为 e(忽略前导零) |
&#O101; / &#o101; |
非标准八进制 | ❌ 不被识别,保留原样 |
javax.swing.text.html.HTMLEditorKit.Parser 及其默认实现不支持八进制数字字符引用,它只遵循 HTML 标准:十进制和十六进制(&#d; 和 &#xh;),如果你需要八进制支持,必须在传递给 Swing 之前手动转换。