README
项目详情
python基础编程 第20章 项目1:自动添加标签
运行
python markup.py < test_input.txt > test_output.html
部分逻辑说明
过滤器 filters 替换特定元素为HTML元素
规则器 rules 根据判定条件,打印特定HTML头尾及Data元素
类型判定规则
1.标题,只包含一行的文本块,长度最多为70个字符,以冒号结束的文本块不属于标题
2.题目,文档中的第一个文本块,前提条件是它属于标题
3.列表项, 以连字符(-)打头的文本块
4.列表,以紧跟在非列表项文本块后面的列表项开头,以后面紧跟着非列表项文本块的列表项结束
注意
规则的先后顺序很重要,比如列表项(li)/列表(ul)
Resource
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def lines(file):
for line in file: yield line
yield '\n'
def blocks(file):
block = []
for line in lines(file):
if line.strip():
block.append(line)
elif block:
yield ''.join(block).strip()
block = []
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Handler:
"""
Handler类是所有处理程序的基类。
"""
# 方法callback根据指定的 前缀 和 名称 查找相应的方法。
def callback(self, prefix, name, *args):
method = getattr(self, prefix + name, None)
if callable(method): return method(*args)
# 辅助方法start,调用callback
def start(self, name):
self.callback('start_', name)
# 辅助方法end,调用callback
def end(self, name):
self.callback('end_', name)
# 方法sub,不调用callback,而是返回一个函数
def sub(self, name):
def substitution(match):
result = self.callback('sub_', name, match)
if result is None: match.group(0)
return result
return substitution
class HTMLRenderer(Handler):
"""
用于渲染HTML的具体处理程序
"""
def start_document(self):
print('<html><head><title>...</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>{}</em>'.format(match.group(1))
def sub_url(self, match):
return '<a href="{}">{}</a>'.format(match.group(1), match.group(1))
def sub_mail(self, match):
return '<a href="mailto:{}">{}</a>'.format(match.group(1), match.group(1))
def feed(self, data):
print(data)
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Rule:
"""
所有规则的基类
"""
def action(self, block, handler):
handler.start(self.type)
handler.feed(block)
handler.end(self.type)
return True
class HeadingRule(Rule):
"""
A heading is a single line that is at most 70 characters and
that doesn't end with a colon.
"""
type = 'heading'
def condition(self, block):
return not '\n' in block and len(block) <= 70 and not block[-1] == ':'
class TitleRule(HeadingRule):
"""
The title is the first block in the document, provided that
it is a heading.
"""
type = 'title'
first = True
def condition(self, block):
if not self.first: return False
self.first = False
return HeadingRule.condition(self, block)
class ListItemRule(Rule):
"""
A list item is a paragraph that begins with a hyphen. As part of the
formatting, the hyphen is removed.
"""
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):
"""
A list begins between a block that is not a list item and a
subsequent list item. It ends after the last consecutive list item.
"""
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 = True
elif self.inside and not ListItemRule.condition(self, block):
handler.end(self.type)
self.inside = False
return False
class ParagraphRule(Rule):
"""
A paragraph is simply a block that isn't covered by any of the other rules.
"""
type = 'paragraph'
def condition(self, block):
return True
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys, re
from handlers import *
from util import *
from rules import *
class Parser:
"""
A Parser 读入文本, 使用 rules and 控制 a handler.
"""
# 初始化成员,handler,rules(),filters()
def __init__(self, handler):
self.handler = handler
self.rules = []
self.filters = []
# 添加rule,方便扩展
def addRule(self, rule):
self.rules.append(rule)
# 添加过滤器, 方便扩展
def addFilter(self, pattern, name):
def filter(block, handler):
return re.sub(pattern, handler.sub(name), block)
self.filters.append(filter)
# 方法parse,读取文本(调用util.py的blocks(file))并分成block,
# 使用循环用规则(rule)和过滤器(filter(block, handler)处理block,
def parse(self, file):
self.handler.start('document')
for block in blocks(file):
for filter in self.filters:
block = filter(block, self.handler)
for rule in self.rules:
if rule.condition(block):
if rule.action(block,
self.handler): break
self.handler.end('document')
# Parser派生出的具体的类(通过添加具体的规则和过滤器):用于添加HTML标记
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实例,构造parser(使用对应的handler)实例,调用parser的方法parser进行对文本的处理
handler = HTMLRenderer()
parser = BasicTextParser(handler)
parser.parse(sys.stdin)