You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java JTextPane Markdown格式化:移除格式定义字符

解决JTextPane中Markdown格式化后残留标记符的问题

我懂你的困扰——现在的代码只是给包含格式标记的文本加了样式,但那些*、__这类标记字符还留在界面上,看起来很违和。问题出在你给整个匹配到的字符串(包括标记符)设置了样式,却没把标记符本身移除。下面是调整后的方案,既能正确应用样式,又能清理掉多余的标记:

核心思路

  1. 用正则分组捕获真正需要格式化的内容(而非包含标记的整段),只给这部分内容设置样式
  2. 倒序处理匹配结果(从后往前修改文档),避免删除字符后导致的索引偏移问题
  3. 精准移除对应的格式标记符

修改后的完整代码

// 注意:所有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 12:52:36