python的即时标记项目练习笔记
admin
2023-07-31 02:12:57
0

这是《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]+@[\\.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、可以用来学习,供我写博文用。

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

    相关内容

    热门资讯

    Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
    500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
    定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
    scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
    65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
    小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
    pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
    微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
    Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
    python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...