Java JTextPane Markdown格式化:移除格式定义字符
解决JTextPane中Markdown格式化后残留标记符的问题
我懂你的困扰——现在的代码只是给包含格式标记的文本加了样式,但那些*、__这类标记字符还留在界面上,看起来很违和。问题出在你给整个匹配到的字符串(包括标记符)设置了样式,却没把标记符本身移除。下面是调整后的方案,既能正确应用样式,又能清理掉多余的标记:
核心思路
- 用正则分组捕获真正需要格式化的内容(而非包含标记的整段),只给这部分内容设置样式
- 倒序处理匹配结果(从后往前修改文档),避免删除字符后导致的索引偏移问题
- 精准移除对应的格式标记符
修改后的完整代码
// 注意:所有Swing文档操作必须在事件调度线程(EDT)中执行 SwingUtilities.invokeLater(() -> { try { String docContents = document.getText(0, document.getLength()); // 处理代码块:|`内容`| Pattern codePattern = Pattern.compile("\\|`(.+?)`\\|"); Matcher codeMatcher = codePattern.matcher(docContents); List<int[]> codeMatches = new ArrayList<>(); while (codeMatcher.find()) { // 存储:标记起始索引、标记结束索引、内容起始索引、内容结束索引 codeMatches.add(new int[]{ codeMatcher.start(), codeMatcher.end(), codeMatcher.start() + 2, codeMatcher.end() - 2 }); } // 倒序处理,避免索引混乱 for (int i = codeMatches.size() - 1; i >= 0; i--) { int[] match = codeMatches.get(i); // 给中间的代码内容设置粗体样式 document.setCharacterAttributes(match[2], match[3] - match[2], BOLD, false); // 先删后面的`|`,再删前面的|` document.remove(match[3], match[1] - match[3]); document.remove(match[0], match[2] - match[0]); } // 处理斜体:*内容* Pattern italicPattern = Pattern.compile("\\*([^\\n*]+)\\*"); Matcher italicMatcher = italicPattern.matcher(document.getText(0, document.getLength())); List<int[]> italicMatches = new ArrayList<>(); while (italicMatcher.find()) { italicMatches.add(new int[]{ italicMatcher.start(), italicMatcher.end(), italicMatcher.start() + 1, italicMatcher.end() - 1 }); } for (int i = italicMatches.size() - 1; i >= 0; i--) { int[] match = italicMatches.get(i); document.setCharacterAttributes(match[2], match[3] - match[2], ITALIC, false); document.remove(match[3], match[1] - match[3]); document.remove(match[0], match[2] - match[0]); } // 处理下划线:__内容__ Pattern underlinePattern = Pattern.compile("__([^\\n_]+)__"); Matcher underlineMatcher = underlinePattern.matcher(document.getText(0, document.getLength())); List<int[]> underlineMatches = new ArrayList<>(); while (underlineMatcher.find()) { underlineMatches.add(new int[]{ underlineMatcher.start(), underlineMatcher.end(), underlineMatcher.start() + 2, underlineMatcher.end() - 2 }); } for (int i = underlineMatches.size() - 1; i >= 0; i--) { int[] match = underlineMatches.get(i); document.setCharacterAttributes(match[2], match[3] - match[2], UNDERLINE, false); document.remove(match[3], match[1] - match[3]); document.remove(match[0], match[2] - match[0]); } // 处理删除线:~~内容~~ Pattern strikePattern = Pattern.compile("~~([^\\n~]+)~~"); Matcher strikeMatcher = strikePattern.matcher(document.getText(0, document.getLength())); List<int[]> strikeMatches = new ArrayList<>(); while (strikeMatcher.find()) { strikeMatches.add(new int[]{ strikeMatcher.start(), strikeMatcher.end(), strikeMatcher.start() + 2, strikeMatcher.end() - 2 }); } for (int i = strikeMatches.size() - 1; i >= 0; i--) { int[] match = strikeMatches.get(i); document.setCharacterAttributes(match[2], match[3] - match[2], STRIKETHROUGH, false); document.remove(match[3], match[1] - match[3]); document.remove(match[0], match[2] - match[0]); } } catch (BadLocationException e) { e.printStackTrace(); } });
关键细节说明
- 倒序处理:每次删除字符都会改变文档长度,如果从前往后处理,后面的匹配索引会直接失效。倒序处理能完美避开这个问题。
- 正则分组:通过
()精准捕获需要格式化的内容,比如\\*([^\\n*]+)\\*中的([^\\n*]+)就是要加斜体的核心文本,前后的*则是要删除的标记。 - EDT线程约束:Swing组件的所有修改操作必须在事件调度线程中执行,否则可能出现线程安全问题或界面渲染异常。
这样处理后,界面上就只会显示带样式的内容,那些Markdown标记符会被完全清理掉啦!
内容的提问来源于stack exchange,提问作者Auxilor
相关产品推荐
相关产品推荐

