1. 程式人生 > >[Python程式設計]綜合性實驗: Java原始碼高亮 實現將Java程式碼轉換為html

[Python程式設計]綜合性實驗: Java原始碼高亮 實現將Java程式碼轉換為html

前言

這個是大三下學期的Java課程設計,目前重構完成了程式碼轉換並輸出的部分.暫時還沒有打算完成視覺化介面.
程式碼不長,加起來也就100行左右(再次感受到Python的精簡),實現了對註釋,關鍵字,字串,一些運算子的高亮.

程式碼實現

import re

class JavaSyntaxHighlighter:
    def __init__(self):
        self.x = 0
        self.line = ""  # 儲存當前處理的行
        self.keywords = \
            ["abstract"
, "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof"
, "int", "interface", "long", "native", "new", "package", "private", "protected", "public", "return", "strictfp", "short", "static", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while"] self.
regexkeywords = [r"(?<=\s)" + w + r"(?=\s)" for w in self.keywords] def highlight_note(self, note): '高亮註釋行' if note != "": # note為空,表示行尾無註釋 self.line = self.line.replace(note, " [note] " + note + " [end] ") def highlight_string(self, pos): '高亮字串' codeline = self.line[:pos] # 程式碼部分 noteline = self.line[pos:] # 不處理行尾註釋 strlist = re.findall(r'\".*?\"|\'.*?\'', codeline) # 搜尋所有字串 if strlist is not None: for string in strlist: codeline = codeline.replace(string, " [str] " + string + " [end] ") self.line = codeline + noteline def highlight_keyword(self, pos): '高亮關鍵字' codeline = " " + self.line[:pos] + " " noteline = self.line[pos:] for r, w in zip(self.regexkeywords, self.keywords): codeline = re.sub(r, " [key] " + w + " [end] ", codeline) self.line = codeline + noteline def highlight_operator(self): '高亮運算子' line = self.line opr = ['=', '(', ')', '{', '}', '|', '+', '-', '*', '/', '<', '>'] for o in opr: line = line.replace(o, " [opr] " + o + " [end] ") # 未實現關於字串內的運算子處理 self.line = line def translate(self, data=""): '轉換為html標籤' name = ["note", "key", "str", "opr"] for n in name: data = data.replace(" [" + n + "] ", "<span class='" + n + "'>") data = data.replace(" [end] ", "</span>") return data def highlight(self, line): '單行程式碼高亮' self.line = line if self.line.strip() == '': return line # 空串不處理 global note # 註釋 note = "" find_note = re.match(r'/(/|\*)(.*)|\*(.*)|(.*)\*/$', self.line.strip()) # 查詢單行註釋 if find_note: # 處理單行註釋 note = find_note.group() self.highlight_note(note) return self.line pos = len(self.line) find_note = re.search(r'(?<=[){};])(.*)/(/|\*).*$', self.line.strip()) # 查詢行尾註釋 if find_note: note = find_note.group() # 標記行尾註釋 pos = find_note.span()[0] # 標記註釋位置 self.highlight_note(note) # 處理行尾註釋 self.highlight_keyword(pos) # 處理關鍵字 self.highlight_string(pos) # 處理字串 self.highlight_operator() # 處理運算子 return self.line # 返回處理好的行 if __name__ == '__main__': jsh = JavaSyntaxHighlighter() html_head = ['<!DOCTYPE html>', '<html>', '<head>', '<title>', 'generated by JavaSyntaxHighlighter', '</title>', '<style type="text/css">', 'pre{font-family:\'Microsoft Yahei\';font-size:20;}', '.key{color:#000080;font-weight:bold;}', '.note{color:#808080;font-weight:bold;font-style:italic;}', '.str{color:#008000;font-weight:bold;}', '.opr{color:#DB380D;font-weight:bold;}', '</style>', '</head>', '<body>', '<pre>'] html_tail = ['</pre>', '</body>', '</html>'] input_file = input("請輸入Java檔案路徑: ") with open(input_file) as f: codelist = f.read().replace("<", "&lt").split('\n') # 替換java中的“<”為html的顯示符 with open(input_file + ".html", 'w') as f: # 儲存html到同目錄 data = [] f.write('\n'.join(html_head)) for i in codelist: data.append(jsh.highlight(i)) # 每行加標籤後存如data f.write(jsh.translate('\n'.join(data))) # 轉換為html的<>標籤 f.write('\n'.join(html_tail)) print("轉換成功!已儲存為:", input_file + ".html")

說明

1.流程:

讀取一個java檔案到列表->對列表每一行呼叫highlight()進行高亮(加標籤)->儲存到data中->
對data中的標籤轉換為html的標準標籤->將html的頭部(<html>,<head>…)+data+html尾部(<head></html>…)輸出為html格式檔案

2.html:

html中使用了<pre>格式化程式碼顯示,使用<span class=“xxx”>進行加標籤
在css中設定class=“xxx"的屬性,實現對不同的部分動態調整顏色,而且只需修改一次就可以了
(以前的版本中使用<font color=”#808080">這類標籤,非常的笨重,不能動態修改顏色,字型等)

3.高亮函式的流程

(1) 呼叫highlight(line),送一行進去
(2) 用self.line = line儲存當前處理的行
(2) self.line.strip()判斷串,空串返回不處理
(3) 用正則模式/(/|\*)(.*)|\*(.*)|(.*)\*/$檢查是否為單行註釋(//xxx /*xxx*/ *xxx xxx*/)
如果是,highlight_note(self.line)高亮註釋部分並返回
(4) 用正則模式(?<=[){};])(.*)/(/|\*).*$查詢行尾註釋,
如果有,返回註釋本身note,以及程式碼與註釋的分割位置pos
例如:int i = 0; //*Note*, note="//*Note*" pos=10
如果沒有,note="" pos=len(self.line)分割位置在行尾
也就是說:self.line[:pos]為程式碼,self.line[pos:]為行尾註釋
(5)highlight_note(note)處理行尾註釋
(6)highlight_keyword(pos)處理關鍵字
(7)highlight_string(pos)處理字串
(8)highlight_operator()處理運算子
(9)最後返回self.line

4.特殊部分處理

例如:
1.字串內含有註釋
string str = "abc//cde/*123*/"
2.註釋內含有字串
// something "i see.."
3.程式碼包含了關鍵字
public void importModule(){}中的import
4.字串\註釋內含運算子
str = "1+5/2*3"
1.含有註釋的字串屬於程式碼行,通過單行註釋的檢查,又通過了行尾註釋的檢查,所以只會被highlight_string()高亮
2.含有字串的註釋,沒通過單行註釋的檢查,被返回.如果通過行尾註釋的檢查,則被分割到註釋部分高亮,不參與highlight_string()的高亮
3.用正則表示式r"(?<=\s)" + w + r"(?=\s)",w為關鍵字即可.
相當於關鍵字w在前面和後面都有不可見字元時"[空白字元a]public[空白字元b]"
對於出現在開頭沒有空白字元的關鍵字要加上一個空格
public static xxx->[空白字元]public static xxx
4.還沒處理…

測試

這裡粘一下Hashmap.java的輸出效果和html原始檔
大概感覺就是這樣了,不過還是有一些問題,想想還有什麼方法好解決?
測試用例Util百度網盤在這裡插入圖片描述
在這裡插入圖片描述

寫在最後

複習了正則表示式的用法,re模組的使用等等,這是第一次重構,將來會有第二,第三次的改進…希望學習Python學得更好