短断断续续学了很久的Python了,一直在看书,没怎么敲过代码,看到最后面十个项目的时候,第一次看这种项目的代码还是很费力的,至少对我是这样,里面有挺多构造器的知识还是以后要深入的了解,还有就是翻译过来的书确实有很多都是语言不通的,读起来,理解起来很费劲。话不多说,我把代码贴上,里面有很详细的注释,还有就是叙述一下整个项目的工作流程,我是看了这个项目看了有4,5遍左右才对这个项目有个整体的了解。
首先,项目的主程序应该就是parser这个类,也就是语法构造器,项目所有的功能都是以这个文件中的类为起点进行的。
首先创建一个处理器的对象,因为在执行parser类中的方法时,当决定了规则和过滤器的时候,是要用handler中的对象进行调用那些方法的。并且要初始化规则和过滤器的队列,以便在检测文件的时候使用。
创建一个主类的对象parser.parse(sys.stdin)
程序运行的时候会在标准输入,也就是屏幕接受程序运行所需要的参数,比如要标记文件的文件名。
然后进入parse方法中执行,每一次利用前面的blocks方法来取文章中的一个块,然后用过滤器和规则来检测这段文本,以至于决定到底要调用什么方法,因为规则是和输出有关的,所以当选定规则之后,这一段文字的标记也就出来了。
markup.py
#coding=utf-8 import sys, re from handlers import * from util import * from rules import * class Parser: """ 整个程序的主类,里面主要是对文本进行相应的语法分析,然后分别用合适的规则和过滤器处理文本,最后输出 """ def __init__(self, handler): """ 初始化程序的处理对象handler以及规则和过滤器存储数组 """ self.handler = handler self.rules = [] self.filters = [] def addRule(self, rule): self.rules.append(rule) def addFilter(self, pattern, name): """ 利用filter创建一个过滤器,过滤器就是一个函数handler.sub(name)。 filters列表每个元素都是一个filter函数,只不过name不同,handler调用的方法也就会不同 """ def filter(block, handler): return re.sub(pattern, handler.sub(name), block) self.filters.append(filter) def parse(self, file): """ 主要的处理程序,程序开始运行最先进入的就是这个函数,是整个程序的入口 """ self.handler.start('document') #处理程序开始写入网页标记的头部 for block in blocks(file): """ 每次读取的都是文本中的一个块 """ for each_filter in self.filters: block = each_filter(block, self.handler) for each_rule in self.rules: if each_rule.condition(block): last = each_rule.action(block, self.handler) if last : break; self.handler.end('document') class BasicTextParser(Parser): """ 为规则和过滤器进行初始化的添加 """ def __init__(self, handler): Parser.__init__(self, handler) self.addRule(ListRule()) self.addRule(ListItemRule()) self.addRule(TitleRule()) self.addRule(HeadingRule()) self.addRule(ParagraphRule()) self.addFilter(r'\*(.+?)\*', 'emphasis') self.addFilter(r'(http://[\.a-zA-Z/]+)', 'url') self.addFilter(r'([\.a-zA-Z]+@[\.a-zA-Z]+[a-zA-Z])', 'mail') handler = HTMLRenderer() parser = BasicTextParser(handler) parser.parse(sys.stdin)
#coding=utf-8 class Handler: """ 当从parser中利用handler对象调用方法的时候就会使用这个类里面的函数 某种意义上说这是整个程序的处理器,由parser发出指令,然后再handler中调用 相应的函数去执行 """ def callback(self, prefix, name, *args): """ prefix是函数的前缀名,name为函数名,args为调用这个函数的参数,*args会接受一些冗余参数 如果要调用的函数存在,那么就返回这个函数,如果没有,那么就自动返回None这也是getattr的作用 """ method = getattr(self, prefix+name, None) if callable(method) : return method(*args) def start(self, name): self.callback('start_', name) def end(self, name): self.callback('end_', name) def sub(self, name): def substitution(match): """ 这个函数会被应用在re.sub中的第二个函数参数来使用 """ result = self.callback('sub_', name, match) if result is None: result = match.group(0) return result return substitution class HTMLRenderer(Handler): def start_document(self): print "<html><head><title>hahaha</title></head><body>" def end_document(self): print "</body></html>" def start_paragraph(self): print "<p>" def end_paragraph(self): print "</p>" def start_heading(self): print "<h2>" def end_heading(self): print '</h2>' def start_list(self): print "<ul>" def end_list(self): print "</ul>" def start_listitem(self): print "<li>" def end_listitem(self): print "</li>" def start_title(self): print "<h1>" def end_title(self): print "</h1>" def sub_emphasis(self, match): return "<em>%s</em>" % match.group(1) def sub_url(self, match): return '<a href = "%s"> %s </a>' % (match.group(1), match.group(1)) def sub_email(self, match): return '<a href = "mailto:%s">%s</a>' % (match.group(1), match.group(1)) def feed(self, data): print data
rules.py
#coding=utf-8 class Rule: """ 所有规则的父类,因为所有的规则类都有action方法,且调用形式几乎一样,所以 在父类中设置一个action函数即可.condition函数用来判断是不是符合该规则,然后通过type和父类中的action函数,调用相应 的处理函数 """ def action(self, block, handler): handler.start(self.type) handler.feed(block) handler.end(self.type) return True class HeadingRule(Rule): type = 'heading' def condition(self, block): return not'\n' in block and len(block) <= 70 and not block[-1] == ':' #回返回是真是假 class TitleRule(HeadingRule): type = 'title' first = True def condition(self, block): if not self.first: return False self.firt = False return HeadingRule.condition(self, block) class ListItemRule(Rule): type = 'listitem' def condition(self, block): return block[0] == '-' def action(self, block, handler): handler.start(self.type) handler.feed(block[1:].strip()) handler.end(self.type) return True class ListRule(ListItemRule): type = 'list' inside = False def condition(self, block): return True def action(self, block, handler): if not self.inside and ListItemRule.condition(self,block): handler.start(self.type) self.inside = 1 elif self.inside and not ListItemRule.condition(self, block): handler.end(self.type) self.inside = False return False class ParagraphRule(Rule): type = 'paragraph' def condition(self, block): return True
#coding=utf-8 def lines(file): for line in file: yield line #每次返回文件中的一行 yield '\n' #在文件的结尾添加一个空行,让程序顺利结束 def blocks(file): """ 程序主要用来收集文本中的块,然后利用各种办法把这一个块加上HTML标记,这个函数的主要用途就是 收集程序的每一个块,提供给程序做相应的处理 """ block = [] for line in lines(file): #依次遍历文件中的每一行 if line.strip(): #如果不是空行,那么就要添加到数组里,这也就是收集块的过程 block.append(line) elif block: #如果是空行,那么就要把当前收集的是一个块的字符串全都添加到一个数组里面返回,并且把数组清空 yield ''.join(block).strip() block = [];
效果如图