[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("<", "<").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學得更好