python的即时标记项目练习笔记

企鹅博客
企鹅博客
企鹅博客
29004
文章
0
评论
2020年9月14日10:47:43 评论 5 views 4401字阅读14分40秒

这是《python基础教程》后面的实践,照着写写,一方面是来熟悉python的代码方式,另一方面是练习使用python中的基本的以及非基本的语法,做到熟能生巧。

这个项目一开始比较简单,不过重构之后就有些复杂了,但是更灵活了。

按照书上所说,重构之后的程序,分为四个模块:处理程序模块,过滤器模块,规则(其实应该是处理规则),语法分析器。

先来说处理程序模块,这个模块的作用有两个,一个是提供那些固定的html标记的输出(每一个标记都有start和end),另一个是对这个标记输出的开始和结束提供了一个友好的访问接口。来看下程序handlers.py:

代码如下:

class Handler:
'''
'''
def callback(self, prefix, name, *args):
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):
result = self.callback('sub_', name, match)
if result is None: match.group(0)
return result
return substitution

class HTMLRenderer(Handler):
'''

'''
def start_document(self):
print '...'
def end_document(self):
print ''
def start_paragraph(self):
print '

'
def end_paragraph(self):
print '

'

def start_heading(self):

print '

'
def end_heading(self):
print '

'

def start_list(self):

print '

    '

    def end_list(self):

    print '

'

def start_listitem(self):

print '

  • '
    def end_listitem(self):
    print '
  • '

    def start_title(self):

    print '

    '
    def end_title(self):
    print '

    '

    def sub_emphasis(self, match):

    return '
    %s' % match.group(1)

    def sub_url(self, match):

    return '%s' % (match.group(1),match.group(1))

    def sub_mail(self, match):

    return '%s' % (match.group(1),match.group(1))

    def feed(self, data):

    print data

    这个程序堪称是整个“项目”的基石所在:提供了标签的输出,以及字符串的替换。理解起来也比较简单。

    再来看第二个模块“过滤器”,这个模块更为简单,其实就是一个正则表达式的字符串。相关代码如下:

    代码如下:

    self.addFilter(r'\*(.+?)\*', 'emphasis')
    self.addFilter(r'(http://[\.a-z0-9A-Z/]+)', 'url')
    self.addFilter(r'([\.a-zA-Z][email protected][\.a-zA-Z]+[a-zA-Z]+)','mail')

    这就是三个过滤器了,分别是:强调牌过滤器(用×号标出的),url牌过滤器,email牌过滤器。熟悉正则表达式的同学理解起来是没有压力的。

    再来看第三个模块“规则”,这个模块,抛开那祖父类不说,其他类应该有的两个方法是condition和action,前者是用来判断读进来的字符串是不是符合自家规则,后者是用来执行操作的,所谓的执行操作就是指调用“处理程序模块”,输出前标签、内容、后标签。 来看下这个模块的代码,其实这个里面几个类的关系,画到类图里面看会比较清晰。 rules.py:

    代码如下:

    class Rule:
    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.first = 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 = True
    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

    补充utils.py:

    代码如下:

    def line(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 = []

    最后隆重的来看下“语法分析器模块”,这个模块的作用其实就是协调读入的文本和其他模块的关系。在往重点说就是,提供了两个存放“规则”和“过滤器”的列表,这么做的好处就是使得整个程序的灵活性得到了极大的提高,使得规则和过滤器变成的热插拔的方式,当然这个也归功于前面在写规则和过滤器时每一种类型的规则(过滤器)都单独的写成了一个类,而不是用if..else来区分。 看代码:

    代码如下:

    import sys, re
    from handlers import *
    from util import *
    from rules import *

    class Parser:
    def __init__(self,handler):
    self.handler = handler
    self.rules = []
    self.filters = []

    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)

    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):
    last = 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-z0-9A-Z/]+)', 'url')
    self.addFilter(r'([\.a-zA-Z][email protected][\.a-zA-Z]+[a-zA-Z]+)','mail')

    handler = HTMLRenderer()
    parser = BasicTextParser(handler)

    parser.parse(sys.stdin)

    这个模块里面的处理思路是,遍历客户端(也就是程序执行的入口)给插进去的所有的规则和过滤器,来处理读进来的文本。

    有一个细节的地方也要说一下,其实是和前面写的呼应一下,就是在遍历规则的时候通过调用condition这个东西来判断是否符合当前规则。

    我觉得这个程序很像是命令行模式,有空可以复习一下该模式,以保持记忆网节点的牢固性。

    最后说一下我以为的这个程序的用途:

    1、用来做代码高亮分析,如果改写成js版的话,可以做一个在线代码编辑器。
    2、可以用来学习,供我写博文用。

    还有其他的思路,可以留下您的真知灼见。
    补充一个类图,很简陋,但是应该能说明之间的关系。另外我还是建议如果看代码捋不清关系最好自己画图,自己画图才能熟悉整个结构。

    继续阅读
    weinxin
    欢迎加入中国站长博客之家
    本站的所有资源都会上传分享到博客之家,希望大家互相学习交流进步。
    Requests库在Python中的用法 python教程

    Requests库在Python中的用法

    前面讲了Python的urllib库的使用和方法,Python网络数据采集Urllib库的基本使用 ,Python的urllib高级用法 。 今天我们来学习下Python中Requests库的用法。 ...
    如何查找python的安装路径 python教程

    如何查找python的安装路径

    我相信一定有很多的人跟我一样,经常忘记Python安装的路径,每当用到的时候,最笨的办法就是在全局电脑里,直接查找Python,这样是肯定能查到的,但是如果你的电脑文件超级多,这将是一个工厂量很大的事...
    怎么查看一个对象的类型 python教程

    怎么查看一个对象的类型

    在Python中有两种类型判断函数,type()和isinstance()。 使用type() 首先,我们来判断对象类型,使用type()函数: 基本类型都可以用type()判断: >>&...
    Python编写生成验证码的脚本的教程 python教程

    Python编写生成验证码的脚本的教程

    在web开发中经常用到验证码,为了防止机器人注册或者恶意登陆和查询等,作用不容小觑 但是验证码其实不是一个函数就能搞定的,它需要生成图片和水印,其实每种语言都有相关的函数生成图片和文字水印。包括我熟悉...
    匿名

    发表评论

    匿名网友 填写信息

    :?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: