Proj1即时标记
本文将介绍如何利用python出色的文本处理能力–包括使用正则表达式将纯文本文件该写成语言中的标记(本文是HTML语言)。
工作与目标
要做的工作基本上是将各种文本元素分类,比如标题和被强调的文本,然后明确地标记它们。本文中是给文本添加HTML标记,使得到的文档能在浏览器中显示并能作为一个网页使用。
工具
-要对文件进行读写,或者从标准输入(sys.stdin)读取,利用print输出
-需要对输入的行进行迭代
-需要一些字符串方法
-需要一个或者两个生成器
-需要用到正则表达式的 re模块
准备工作
开始编码前,编写一个测试文件test_input.txt(本文所提到的所有文件都可以从该链接下载proj1即时标记)
初次实现
基本思路是先把文本分成段落,再根据不同的段落属性添加标记。
找出文本块(段落)
找出块的一个简单方法就是收集遇到的所有行,直到遇到一个空行,然后返回已经收集的行。注意:必须确保文件最后一行是空行,否则程序不知道最后一个块什么时候结束。util.py文件是一个文本块生成器,其中的lines(file)函数实现了添加空行的功能,blocks(file)实现了找出段落的功能。
添加标记
该部分见文件simple_markup.py,这个简单版本只能标记标题和段落两种元素。下面是更完善的版本。
再次实现
列出一些模块:
-语法分析器。用来读取文本,管理其他类的对象。
-规则。可以为每个种类的块制定一条规则,能检测使用的块类型并且进行适当的格式化。
-过滤器。使用过滤器来包装一些处理内嵌元素(如url)的正则表达式.
-处理程序。语法分析器使用处理程序来产生输出。每个处理程序能产生不同种类的标记。
处理程序
负责产生标记文本。每个类型有一对方法:开始和结束块。如下面的方式:
def start_paragraph(self):
print '<p>'
def end_paragraph(self):
print '</p>'
类似上面这段代码都被封装在HTMLRenderer类中,该类继承了Handler类。这个超类管理具体的子类的方法的调用。比如要调用start_paragraph(),就把这两个单词作为单独的字符串,再合在一起作为函数名,查找该函数是否可以调用。如下所示:
def start(self,name):
self.callback('start_',name)
def end(self,name):
self.callback('end_',name)
def sub(self,name):
def substitution(match):
result = self.callback('sub_',name,match)
if result is None:
match.group(0)
return result
return substitution
其中的sub函数不直接调用callback,而是返回一个新的函数,这个函数会被当成re.sub中的替换函数来使用(这就是采用一个匹配的对象作为唯一参数的原因)。
规则
规则必须具备如下功能:
-能识别自己是用于哪种块
-能对块进行转换(操作)
因此每个规则对象都有两个方法,condition和action。除了列表,其他段落属性都具有相同的操作,把这些相同的操作作为基类Rule的方法,具体的段落属性都继承这个基类。
class Rule:
"""
所有规则的基类。
"""
def action(self,block,handler):
handler.start(self.type)
handler.feed(block)
handler.end(self.type)
return True
语法分析器(parser)
Parser类使用一个处理程序、一系列规则和过滤器(处理内嵌元素url等)将纯文本文件转换成标记文件,控制整个工程的行为。BasicTextParser类是Parser类的子类,负责添加具体的规则和过滤器
总结
笔者不太懂HTML语法格式,不过参考文中给出的W3C上Dave Raggett所写的优秀简介Get Start with HTML还是略有收获。