本文目录导读:

我来详细解释 JEditorPane、HTMLEditorKit 的字符解析机制:
基础架构
import javax.swing.*;
import javax.swing.text.html.*;
import javax.swing.text.*;
import java.io.*;
public class HTMLCharParserExample {
public static void main(String[] args) {
JEditorPane editor = new JEditorPane();
editor.setEditorKit(new HTMLEditorKit());
// 设置HTML内容
String html = "<html><body>Hello & World <test></body></html>";
editor.setText(html);
}
}
字符解析机制
1 HTML实体解析
// HTMLEditorKit的内置解析器
HTMLEditorKit.Parser parser = new HTMLEditorKit.Parser() {
@Override
public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet)
throws IOException {
// 默认解析器实现
}
};
// 常见HTML实体的解析
Map<String, Character> htmlEntities = new HashMap<>() {{
put("&", '&');
put("<", '<');
put(">", '>');
put(""", '"');
put(" ", ' '); // 非断行空格
put("'", '\'');
put("©", '©');
put("®", '®');
put("€", '€');
put("£", '£');
put("¥", '¥');
}};
2 自定义字符解析器
class CustomCharParser extends HTMLEditorKit.Parser {
private static final Pattern ENTITY_PATTERN =
Pattern.compile("&(#\\d+|#x[0-9a-fA-F]+|[a-zA-Z]+);");
@Override
public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet)
throws IOException {
BufferedReader br = new BufferedReader(r);
String line;
StringBuilder content = new StringBuilder();
while ((line = br.readLine()) != null) {
content.append(line).append("\n");
}
String processedContent = processEntities(content.toString());
// 解析处理后的内容
processHTMLContent(processedContent, cb);
}
private String processEntities(String html) {
StringBuffer result = new StringBuffer();
Matcher matcher = ENTITY_PATTERN.matcher(html);
while (matcher.find()) {
String entity = matcher.group(1);
String replacement = resolveEntity(entity);
matcher.appendReplacement(result, replacement);
}
matcher.appendTail(result);
return result.toString();
}
private String resolveEntity(String entity) {
if (entity.startsWith("#x")) {
// 十六进制字符引用
int codePoint = Integer.parseInt(entity.substring(2), 16);
return String.valueOf((char) codePoint);
} else if (entity.startsWith("#")) {
// 十进制字符引用
int codePoint = Integer.parseInt(entity.substring(1));
return String.valueOf((char) codePoint);
} else {
// 命名实体引用
return resolveNamedEntity(entity);
}
}
private String resolveNamedEntity(String name) {
Map<String, String> entityMap = new HashMap<>();
entityMap.put("amp", "&");
entityMap.put("lt", "<");
entityMap.put("gt", ">");
// 更多实体映射...
return entityMap.getOrDefault(name, "&" + name + ";");
}
}
字符编码处理
class CharEncodingHandler {
public static void setEncoding(JEditorPane editor, String encoding) {
HTMLEditorKit kit = (HTMLEditorKit) editor.getEditorKit();
// 设置文档属性
Document doc = kit.createDefaultDocument();
doc.putProperty("charset", encoding);
// 设置字符集
editor.setDocument(doc);
// 设置内容类型
editor.setContentType("text/html; charset=" + encoding);
}
public static String detectEncoding(byte[] data) {
// 检测BOM
if (data.length >= 3) {
if (data[0] == (byte)0xEF && data[1] == (byte)0xBB && data[2] == (byte)0xBF) {
return "UTF-8";
} else if (data[0] == (byte)0xFF && data[1] == (byte)0xFE) {
return "UTF-16LE";
} else if (data[0] == (byte)0xFE && data[1] == (byte)0xFF) {
return "UTF-16BE";
}
}
return "ISO-8859-1"; // 默认编码
}
}
特殊字符处理示例
public class SpecialCharDemo {
public static void main(String[] args) {
JEditorPane editor = new JEditorPane();
editor.setEditorKit(new HTMLEditorKit());
// 测试各种字符
String testHtml = """
<html>
<body>
<h3>特殊字符测试</h3>
<p>1. HTML实体: & < > "</p>
<p>2. 数字引用: A A ☃</p>
<p>3. Unicode字符: \u2603 \u00A9 \u20AC</p>
<p>4. 控制字符: 制表符\t 换行\n</p>
</body>
</html>
""";
editor.setText(testHtml);
// 监听文档变化
editor.getDocument().addDocumentListener(new javax.swing.event.DocumentListener() {
@Override
public void insertUpdate(javax.swing.event.DocumentEvent e) {
analyzeChars(editor);
}
@Override
public void removeUpdate(javax.swing.event.DocumentEvent e) {}
@Override
public void changedUpdate(javax.swing.event.DocumentEvent e) {}
});
}
private static void analyzeChars(JEditorPane editor) {
try {
String text = editor.getDocument().getText(
0, editor.getDocument().getLength());
System.out.println("字符串分析:");
System.out.println("原始文本: " + text);
System.out.println("字符数量: " + text.length());
// 分析每个字符
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
System.out.printf("位置 %3d: U+%04X '%c' %s%n",
i, (int)c,
Character.isISOControl(c) ? '.' : c,
getCharCategory(c));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static String getCharCategory(char c) {
if (Character.isLetter(c)) return "字母";
if (Character.isDigit(c)) return "数字";
if (Character.isWhitespace(c)) return "空白";
if (Character.isISOControl(c)) return "控制字符";
return "其他";
}
}
性能优化和缓存
class CharCacheManager {
private static final int MAX_CACHE_SIZE = 10000;
private static final LinkedHashMap<String, String> entityCache =
new LinkedHashMap<String, String>(MAX_CACHE_SIZE, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > MAX_CACHE_SIZE;
}
};
private static final Map<String, Character> charCache = new HashMap<>();
static {
// 预加载常用字符
charCache.put("&", '&');
charCache.put("<", '<');
charCache.put(">", '>');
charCache.put(""", '"');
}
public static synchronized String getOrParse(String entity) {
// 检查缓存
String cached = entityCache.get(entity);
if (cached != null) {
return cached;
}
// 解析并缓存
String parsed = parseEntity(entity);
entityCache.put(entity, parsed);
return parsed;
}
private static String parseEntity(String entity) {
// 实现具体的解析逻辑
if (entity.startsWith("&#")) {
try {
int codePoint = Integer.parseInt(
entity.substring(2, entity.length() - 1));
return String.valueOf((char) codePoint);
} catch (NumberFormatException e) {
return entity;
}
}
return entity;
}
}
完整的解析示例
public class CompleteCharParserExample {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("HTML字符解析示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JEditorPane editor = new JEditorPane();
editor.setEditorKit(new HTMLEditorKit());
// 创建一个包含各种字符的HTML
String htmlContent = createTestHTML();
editor.setText(htmlContent);
// 添加滚动面板
JScrollPane scrollPane = new JScrollPane(editor);
// 添加控制面板
JPanel controlPanel = new JPanel();
JButton analyzeBtn = new JButton("分析字符");
analyzeBtn.addActionListener(e -> analyzeCharacters(editor));
controlPanel.add(analyzeBtn);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(controlPanel, BorderLayout.SOUTH);
frame.setSize(600, 400);
frame.setVisible(true);
});
}
private static String createTestHTML() {
return """
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h2>HTML字符解析测试</h2>
<p>HTML实体: & < > " '</p>
<p>数字引用: A B C (ASCII A, B, C)</p>
<p>十六进制: A B C</p>
<p>特殊符号: © ® € £ ¥</p>
<p>Unicode: ★ ☆ ♠ ♥ ♦ ♣</p>
<p>数学符号: ∑ ∏ √ ∞</p>
<pre>
保留字符: < > &
空格: 非断行空格
</pre>
</body>
</html>
""";
}
private static void analyzeCharacters(JEditorPane editor) {
try {
Document doc = editor.getDocument();
String text = doc.getText(0, doc.getLength());
System.out.println("===== 字符分析结果 =====");
System.out.println("总字符数: " + text.length());
// 分类统计
Map<String, Integer> categoryCount = new HashMap<>();
for (char c : text.toCharArray()) {
String category;
if (Character.isLetter(c)) category = "字母";
else if (Character.isDigit(c)) category = "数字";
else if (Character.isWhitespace(c)) category = "空白";
else if (Character.isISOControl(c)) category = "控制";
else category = "符号";
categoryCount.merge(category, 1, Integer::sum);
}
System.out.println("字符类别统计:");
categoryCount.forEach((k, v) ->
System.out.println(" " + k + ": " + v));
// 显示所有非ASCII字符
System.out.println("\n非ASCII字符:");
for (char c : text.toCharArray()) {
if (c > 127) {
System.out.printf(" U+%04X: '%c'%n", (int)c, c);
}
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
这个解析机制提供了:
- 自动实体解析 - HTML字符实体的自动转换
- 编码支持 - 多字符集编码处理
- 性能优化 - 缓存机制提高解析效率
- 灵活扩展 - 支持自定义解析规则
- 错误处理 - 健壮的错误处理机制
需要注意的问题是:
- 默认解析器可能不支持所有HTML5实体
- 大文档解析可能影响性能
- 特殊字符的处理需要谨慎
- 编码声明可能被忽略
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播