html 中 Java 代码的语法高亮显示

Posted

技术标签:

【中文标题】html 中 Java 代码的语法高亮显示【英文标题】:Syntax-Highlighting for Java-Code in html 【发布时间】:2020-11-08 15:13:23 【问题描述】:

我要做什么

我正在开发一个突出显示 html 中 java 代码的语法高亮器(示例如下)。

示例输出

我已经使用以下 java-code (caesar-encryption) 测试了代码:

//Encryption
public static String encrypt(String text, int n) 
    int x = 0;
    int y = 0;
    String out = ""; //Empty string for result.
    while (x < text.length()) 
        if (text.charAt(x) > 64 && text.charAt(x) < 91) 
            if (text.charAt(x) + n > 90) 
                y = 26;
            
            out = out + (char) (text.charAt(x) + n - y);
         else 
            out = out + text.charAt(x);
        
        x++;
        y = 0;
    
    return out;

输出如下所示:

<!-- Code begins here -->
<div style = "background: LightGray; font: monospace; width: fit-content; height: min-height;"><pre><code>
<span style='color:green; font-weight:bold; '>//Encryption
</span><span style='color:#7f0055; font-weight:bold; '>public</span> <span style='color:#7f0055; font-weight:bold; '>static</span> <span style='color:#7f0055; font-weight:bold; '>String</span> encrypt(<span style='color:#7f0055; font-weight:bold; '>String</span> text, <span style='color:#7f0055; font-weight:bold; '>int</span> n) 
    <span style='color:#7f0055; font-weight:bold; '>int</span> x = 0;
    <span style='color:#7f0055; font-weight:bold; '>int</span> y = 0;
    <span style='color:#7f0055; font-weight:bold; '>String</span> out = <span style='color:blue; font-weight:bold; '>""</span>; <span style='color:green; font-weight:bold; '>//Empty string <span style='color:#7f0055; font-weight:bold; '>for</span> result.
</span>    <span style='color:#7f0055; font-weight:bold; '>while</span> (x < text.length()) 
        <span style='color:#7f0055; font-weight:bold; '>if</span> (text.charAt(x) > 64 && text.charAt(x) < 91) 
            <span style='color:#7f0055; font-weight:bold; '>if</span> (text.charAt(x) + n > 90) 
                y = 26;
            
            out = out + (<span style='color:#7f0055; font-weight:bold; '>char</span>) (text.charAt(x) + n - y);
         <span style='color:#7f0055; font-weight:bold; '>else</span> 
            out = out + text.charAt(x);
        
        x++;
        y = 0;
    
    <span style='color:#7f0055; font-weight:bold; '>return</span> out;

</pre></code></div>
<!-- Code ends here -->

如果你用浏览器打开这段代码,它看起来像这样:

代码

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;

public class Gui 

  private JTextArea inputArea;
  private JTextArea outputArea;
  private boolean inputAreaClicked = false;

  public Gui() 
    //JFrame
    JFrame frame = new JFrame("Syntax-Highlighter");
    frame.setSize(700, 700);
    frame.setMinimumSize(new Dimension(700, 700));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    

    //JPanel
    JPanel panel = new JPanel(new GridBagLayout());
    
    //Creating textArea for input
    inputArea = new JTextArea("Enter text here...");
    inputArea.setLineWrap(true);
    inputArea.setTabSize(1);
    inputArea.setFont(new Font("monospaced", Font.ITALIC, 12));
    inputArea.addMouseListener(new MouseAdapter()      //Set text to "" the first time the inputArea is clicked
      @Override
      public void mouseClicked(MouseEvent e)
        if(!inputAreaClicked) 
          inputArea.setText("");
          inputArea.setFont(new Font("monospaced", Font.PLAIN, 12));
          inputAreaClicked = true;
        
      
    );
    JScrollPane input = new JScrollPane(inputArea);
    input.setPreferredSize(new Dimension(600, 110));
    input.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    input.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);

    //Creating buttons
    
    JPanel buttonPanel = new JPanel(new FlowLayout(0, 50, 10)); //FlowLayout(align, hgap, vgap)
    JButton button = new JButton("Highlight");
    button.setFont(new Font("Arial", Font.PLAIN, 20));
    button.addActionListener(e -> hightlight(inputArea.getText()));
    button.setPreferredSize(new Dimension(140,30));
   
    //Creating textArea for output
    outputArea = new JTextArea();
    outputArea.setEditable(false);
    outputArea.setTabSize(1);
    outputArea.setLineWrap(false);
    outputArea.setFont(new Font("monospaced", Font.PLAIN, 12));
    JScrollPane output = new JScrollPane(outputArea);
    output.setPreferredSize(new Dimension(600, 400));
    output.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    output.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);

    //Layout
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.weighty = 5;
    gbc.gridwidth = GridBagConstraints.REMAINDER;

    //Add everything to panel
    buttonPanel.add(button);
    
    panel.add(input, gbc);
    panel.add(buttonPanel, gbc);
    panel.add(output, gbc);
    
    //Add everything to frame
    frame.add(panel, BorderLayout.CENTER);
    frame.setVisible(true);
  

  private void hightlight(String text) 
    //Keywords
    String[] array = 
        "abstract", "assert", "boolean", "break", "byte", "case", 
        "catch", "char", "class", "const", "continue", "default", "do", 
        "double", "else", "enum", "extends", "false", "final", "finally", "float",
        "for", "goto", "if", "implements", "import", "instanceof", "int", 
        "interface", "long", "native", "new", "null", "package", "private", "protected",
        "public", "return", "short", "static", "String", "strictfp", "super", "switch", "synchronized", 
        "System", "this", "throw", "throws", "transient", "true", "try", "void", "volatile", "while"
    ;
    
    //Highlight every keyword with color:#7f0055
    for(int i = 0; i < array.length; i++) 
      text = text.replaceAll(array[i] + "(?![a-zA-Z])", "<span style='color:#7f0055; font-weight:bold; '>" + array[i] + "</span>");

    
    //Highlight Strings
    text = text.replaceAll("\"(?<render>.*?)\"", "<span style='color:blue; font-weight:bold; '>" + "\"$render\"" + "</span>");
    
    //Highlight import-statements
    text = text.replaceAll("import(?<render>.*?);", "<span style='color:#7f0055; font-weight:bold; '>" + "import$render;" + "</span>");
    
    //Highlight multiline-comments
    Pattern p = Pattern.compile("/\\*(?<render>.*?)\\*/", Pattern.DOTALL);
    Matcher m = p.matcher(text);
    text = m.replaceAll("<span style='color:green; font-weight:bold; '>" + "/\\*$render\\*/" + "</span>");
    
    //Highlight single-line-comments
    text = text.replaceAll("//(?<render>.*?)\n", "<span style='color:green; font-weight:bold; '>" + "//$render\n" + "</span>");
    
    text = "<!-- Code begins here -->\n<div style = \"background: LightGray; font: monospace; width: fit-content; height: min-height;\"><pre><code>\n" 
        + text + "\n</pre></code></div>\n<!-- Code ends here -->\n";
    outputArea.setText(text);
  

问题

如上图所示,cmets中的关键字仍然以关键字高亮显示。

您知道如何解决这个问题吗?

我的尝试

我尝试使用以下代码(在反向引用中替换),但没有成功:

// Highlight single-line-comments
text = text.replaceAll("//(?<render>.*?)\n", "<span style='color:green; font-weight:bold; '>"
        + "//" + "$render".replaceAll("color: #7f0055", "color: green") + "\\n</span>");

很遗憾,这不起作用?如何纠正?

【问题讨论】:

一个相当老套的解决方案:&lt;span style='color:green !important; font-weight:bold; '&gt;. @Sweeper 不幸的是,这没有帮助。你有别的想法吗? 要正确突出 Java 代码,您需要正确解析它,没有任何 hacky 解决方案可以解决所有问题(想想多行 cmets ... Java 字符串文字 ...)。 【参考方案1】:

我建议遍历文本,一次处理一个标记:

为要检测的不同类型的输入定义正则表达式列表,以 \\G 开头强制从输入开始进行匹配 为您想要跳过的内容添加一个表达式,这样即使您没有找到任何要突出显示的内容,您也能取得进展 对内容有一个外循环,对表达式列表有一个内循环。对于每个检测到的类型,从输入中删除匹配的字符串,将替换添加到输出并推进外循环。

第 1 步中的列表实际上应该是对应 HTML 替换字符串的映射。

附:该过程基于标记化,类似于 Java 解析器在最低级别所做的 - 我认为您不需要完整的 Java 解析器(正如其中一个 cmets 所建议的那样)。分离输入和输出确保您无需担心双重处理输入,还允许您正确地对输出进行 HTML 转义(这很重要,因为 cmets 和字符串可能包含 HTML)。

【讨论】:

以上是关于html 中 Java 代码的语法高亮显示的主要内容,如果未能解决你的问题,请参考以下文章

如何向 VuePress 添加代码高亮?

前端向blog或网站中添加语法高亮显示代码方法总结

Objective C 的 Javascript 语法高亮显示

C++语法高亮html生成器

Word文档中的语法高亮显示代码

codemirror 怎么对java高亮