[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学得更好