在java中的JEditorPane中突出显示语法

时间:2010-11-11 06:39:14

标签: java regex swing syntax-highlighting

我想在jEditorPane中执行语法高亮显示。它允许我执行单行语法高亮显示,但如果XML标记被拆分为两行或更多行,则它不起作用。下面是我用于语法突出显示的代码。帮助我解决这个问题。感谢.....

public class XmlView extends PlainView {

    private static HashMap<Pattern, Color> patternColors;
    private static String TAG_PATTERN = "(</?[A-Za-z\\-_0-9]*)\\s?>?";
    private static String TAG_END_PATTERN = "(/>)";
    private static String TAG_ATTRIBUTE_PATTERN = "\\s(\\w*)\\=";
    private static String TAG_ATTRIBUTE_VALUE = "[a-z\\-]*\\=(\"[^\"]*\")";
    private static String TAG_COMMENT = "(<\\!--[\\w * \\S]*-->)";
    private static String TAG_CDATA = "(<\\!\\[CDATA\\[.*\\]\\]>)";

    static {
        // NOTE: the order is important!
        patternColors = new LinkedHashMap<Pattern, Color>();
        patternColors.put(Pattern.compile(TAG_PATTERN), new Color(163, 21, 21));
        patternColors.put(Pattern.compile(TAG_CDATA), Color.GRAY);
        patternColors.put(Pattern.compile(TAG_ATTRIBUTE_PATTERN), new Color(127, 0, 127));
        patternColors.put(Pattern.compile(TAG_END_PATTERN), new Color(63, 127, 127));
        patternColors.put(Pattern.compile(TAG_ATTRIBUTE_VALUE), new Color(42, 0, 255));
        patternColors.put(Pattern.compile(TAG_COMMENT), new Color(0, 128, 0));
    }

    public XmlView(Element element) {

        super(element);

        // Set tabsize to 4 (instead of the default 8)
        getDocument().putProperty(PlainDocument.tabSizeAttribute, 4);
    }

    @Override
    protected int drawUnselectedText(Graphics graphics, int x, int y, int p0,
            int p1) throws BadLocationException {

        Document doc = getDocument();
        String text = doc.getText(p0, p1 - p0);

        Segment segment = getLineBuffer();

        SortedMap<Integer, Integer> startMap = new TreeMap<Integer, Integer>();
        SortedMap<Integer, Color> colorMap = new TreeMap<Integer, Color>();

        // Match all regexes on this snippet, store positions
        for (Map.Entry<Pattern, Color> entry : patternColors.entrySet()) {

            Matcher matcher = entry.getKey().matcher(text);

            while (matcher.find()) {
                startMap.put(matcher.start(1), matcher.end());
                colorMap.put(matcher.start(1), entry.getValue());
            }
        }

        // TODO: check the map for overlapping parts

        int i = 0;

        // Colour the parts
        for (Map.Entry<Integer, Integer> entry : startMap.entrySet()) {
            int start = entry.getKey();
            int end = entry.getValue();

            if (i < start) {
                graphics.setColor(Color.black);
                doc.getText(p0 + i, start - i, segment);
                x = Utilities.drawTabbedText(segment, x, y, graphics, this, i);
            }

            graphics.setColor(colorMap.get(start));
            i = end;
            doc.getText(p0 + start, i - start, segment);
            x = Utilities.drawTabbedText(segment, x, y, graphics, this, start);
        }

        // Paint possible remaining text black
        if (i < text.length()) {
            graphics.setColor(Color.black);
            doc.getText(p0 + i, text.length() - i, segment);
            x = Utilities.drawTabbedText(segment, x, y, graphics, this, i);
        }

        return x;
    }

}

2 个答案:

答案 0 :(得分:3)

标签,评论和CDATA部分的正则表达式需要分为两部分:

Pattern TAG_START     = Pattern.compile("</?[\\w-]+");
Pattern TAG_END       = Pattern.compile("/?>");
Pattern COMMENT_START = Pattern.compile("<!--");
Pattern COMMENT_END   = Pattern.compile("-->");
Pattern CDATA_START   = Pattern.compile("<\\[CDATA\\[");
Pattern CDATA_END     = Pattern.compile("\\]\\]>");

每当你对其中一个*_START模式进行匹配时,就会设置一个标志,表明你处于不同的模式。例如,TAG_START上的匹配会使您处于TAG模式,这意味着您在标记内。每种模式都有自己的一组模式,有些模式与其他模式共享,有些模式特定。

例如,在默认模式下,您可以查找上面列出的*_START模式,以及其他适合的模式。在TAG模式下,您可以查找属性/值对以及TAG_END模式,这些模式在标记之外没有意义。并且您始终首先查找TAG_END模式 ,以确保您确实仍在标记中。 (或者以*_END模式适用于您所处的模式。)

由于模式可以跨行界限持续存在,这意味着您必须在绘制一行和绘制下一行(复杂)之间保存一些状态,或者每次绘制一条线(慢)时扫描整个文档。无论采用哪种方法,性能在很大程度上取决于正则表达式的质量。例如,你的正则表达式:

"(<\\!--[\\w * \\S]*-->)"

...最初会消耗从<!--到文档末尾的所有内容,只需要在很长的路上进行回溯。此外,如果有两个或更多注释,它将从第一个的开头到最后一个的结尾匹配。出于这两个原因,我会这样写:

"<!--[^-]*+(?>-(?!->))*+-->"

注意使用所有格量词(*+)和原子组((?>...))。从正确的角度来看,它们不是必需的,但它们使正则表达式更有效率,这在这个项目中尤为重要。

还有一件事:如果你打算使用find(),你还应该将\G(最后一个匹配的锚点)添加到每个正则表达式的开头,就像弗里德在this regex from his book做了。

答案 1 :(得分:0)

您可能需要使用Pattern.MULTILINE标志吗?

e.g。

Pattern.compile(TAG_PATTERN, Pattern.MULTILINE)