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


Posted in Python onSeptember 18, 2014

这是《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 '<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>%s</em>' % match.group(1)

    def sub_url(self,  match):

        return '<a href="%s">%s</a>' % (match.group(1),match.group(1))

    def sub_mail(self,  match):

        return '<a href="mailto:%s">%s</a>' % (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]+@[\.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]+@[\.a-zA-Z]+[a-zA-Z]+)','mail')
handler = HTMLRenderer()

parser = BasicTextParser(handler)
parser.parse(sys.stdin)

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

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

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

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

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

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

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

Python 相关文章推荐
Python代理抓取并验证使用多线程实现
May 03 Python
python3访问sina首页中文的处理方法
Feb 24 Python
Python下Fabric的简单部署方法
Jul 14 Python
Python中使用haystack实现django全文检索搜索引擎功能
Aug 26 Python
浅谈python中copy和deepcopy中的区别
Oct 23 Python
pycharm+PyQt5+python最新开发环境配置(踩坑)
Feb 11 Python
Python类中的魔法方法之 __slots__原理解析
Aug 26 Python
Django后台管理系统的图文使用教学
Jan 20 Python
使用Tkinter制作信息提示框
Feb 18 Python
Python通过Tesseract库实现文字识别
Mar 05 Python
基于OpenCV的路面质量检测的实现
Nov 04 Python
Python Django / Flask如何使用Elasticsearch
Apr 19 Python
python脚本实现分析dns日志并对受访域名排行
Sep 18 #Python
python中的字典详细介绍
Sep 18 #Python
python中执行shell命令的几个方法小结
Sep 18 #Python
python处理PHP数组文本文件实例
Sep 18 #Python
Python threading多线程编程实例
Sep 18 #Python
Python中捕捉详细异常信息的代码示例
Sep 18 #Python
python字符串连接的N种方式总结
Sep 17 #Python
You might like
PHP中$_SERVER使用说明
2015/07/05 PHP
一个javascript图片阅览组件
2010/11/09 Javascript
读jQuery之二(两种扩展)
2011/06/11 Javascript
jQuery的slideToggle方法实例
2013/05/07 Javascript
JavaScript实现信用卡校验方法
2015/04/07 Javascript
jQuery实现彩带延伸效果的网页加载条loading动画
2015/10/29 Javascript
JavaScript生成二维码图片小结
2015/12/27 Javascript
jQuery插件datatables使用教程
2016/04/21 Javascript
jquery表单提交带错误信息提示效果
2017/03/09 Javascript
使用Xcache缓存器加速PHP网站的配置方法
2017/04/22 Javascript
记一次Vue.js混入mixin的使用(分权限管理页面)
2019/04/17 Javascript
pyqt4教程之messagebox使用示例分享
2014/03/07 Python
Python实现基于KNN算法的笔迹识别功能详解
2018/07/09 Python
python字典改变value值方法总结
2019/06/21 Python
关于Python形参打包与解包小技巧分享
2019/08/24 Python
python 3.74 运行import numpy as np 报错lib\site-packages\numpy\__init__.py
2019/10/06 Python
Python新手学习raise用法
2020/06/03 Python
解决Keras中CNN输入维度报错问题
2020/06/29 Python
手把手教你从PyCharm安装到激活(最新激活码),亲测有效可激活至2089年
2020/11/25 Python
解决CSS3的opacity属性带来的层叠顺序问题
2016/05/09 HTML / CSS
HTML5 CSS3新的WEB标准和浏览器支持
2009/07/16 HTML / CSS
美国摄影爱好者购物网站:Focus Camera
2016/10/21 全球购物
澳大利亚游乐场设备品牌:Lifespan Kids
2019/05/24 全球购物
美国在线购买和出售礼品卡网站:EJ Gift Cards
2019/06/09 全球购物
采购内勤岗位职责
2013/12/10 职场文书
技能竞赛活动方案
2014/02/21 职场文书
客服部班长工作责任制
2014/02/25 职场文书
篝火晚会主持词
2014/03/25 职场文书
槐乡的孩子教学反思
2014/04/27 职场文书
2014小学语文教学工作总结
2014/12/17 职场文书
幼儿园六一儿童节演讲稿
2015/03/19 职场文书
火锅店的开业营销方案范本!
2019/07/05 职场文书
申论不会写怎么办?教您掌握这6点思维和原则
2019/07/17 职场文书
python_tkinter弹出对话框创建
2022/03/20 Python
Tomcat用户管理的优化配置详解
2022/03/31 Servers
Ubuntu18.04下QT开发Android无法连接设备问题解决实现
2022/06/01 Java/Android