文章标题

来源:互联网 发布:上海华腾软件怎么样 编辑:程序博客网 时间:2024/05/01 05:19

Python基础项目1:即使标记

现在来梳理一下程序运行分析
首先在markup.py中,只有三句运行语句,其余的都是关于类的定义,具体三个语句如下:

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

在windows状态下,命令如下。命令分析:用python运行markup.py,用<后面的内容作为输入,用>后面的内容作为输出。简而言之,将test_input.txt输入到markup.py中,输出到test_output1.py中。

python markup.py <test_input.txt >test_output1.html

其实呢,会发现语句从self.handler.start(‘document’)开始运行。blocks是函数,由于含有yield,则将变成迭代器,可以在循环语句中使用了。根据blocks的定义,block的内容为一段文字。接下来有两个循环:

for block in blocks(file):    for filter in self.filters:        block = filter(block, self.handle)    for rule in self.rules:        if rule.condition(block):            last = rule.action(block, self.handler)            if last:                break

第一个是filters,这一个循环主要是筛选器的作用,分辨block中是否有符合的正则表达式,接着进行相应的替换。根据其循环的内容block = filter(block, self.handle),去查找filter函数,函数内容如下:

def filter(block, handler):    return re.sub(pattern, handler.sub(name), block)

会发现调用了re.sub函数,其中需要提供三个参数,只有pattern和name参数不清楚从哪里来的。原来filter函数定义在addFilter函数下,属于Parser类,而在Parser类下有一子类BasicTextParser,其中有许多魔法方法,如下。可见其中给addFilter函数提供了三个语句,分别是用来捕捉强调内容、链接和邮箱的。回到上面所讲的筛选器循环,他会执行三次filter函数,每一次对应的是捕捉不同的内容,若有则进行相应的替换,否则便相当于身体检查,没事,什么也没动。

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]+)', 'mail')

接下来看第二个循环—rule,和第一个循环类似,在BasicTextParser类中,提供了有5种rule,判断该block是否为是列表、是否在列表内、是否为标题、是否为头标题和是否为正文,由于存在有顺序,以下将用两个block来观察其运行情况。

Welcome to World Wide Spam, Inc.

这是文中的第一句,进入第一个筛选器filter循环,会发现没有与正则表达式所匹配的;进入第二个rule循环:rule.condition(block),第一次是ListRule,毫不犹豫地返回True,继续执行下一句,也就是if语句下的内容:

last = rule.action(block, self.handler)

再查看ListRule中的action函数,如下:

    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

if条件符不符合呢?self.inside = False,not self.inside说明还需看and后面的条件,这时跳转到了ListItemRule.condition函数具体如下:

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

判断block[0] == ‘-‘,也就是判断是否是列表内容咯,显然不是嘛,开头没有’-‘,没戏了,也就是说and后面为False,可以看看是否符不符合elif呢?结果一看self.inside就蒙眼了,False,返回False,即last = False,随后判断if last也省去了,进入下一个rule的判断;接下来是ListItemRule,先看ListItemRule.condition,据上面的分析,不符和条件,直接返回False,直接进入下一个rule—TitleRule,这看来好像有点戏,继续进行分析,TitleRule内容如下:

lass TitleRule(HeadingRule):    """    题目是文档的第一个块,但前提是它是大标题    """    type = 'title'    first = True    def condition(self, block):        if not self.first:            return False        self.first = False        return HeadingRule.condition(self, block)

看看TitleRule.condition,if语句,first为True,not first为False,不执行if语句,继续下一行,self.first= True,不明其意,继续下一行HeadingRule.condition,那只好去看看呗,内容如下:

class HeadingRule(Rule):    """    标题占一行,最多70个字符,并且不以冒号结尾。    """    type = 'heading'    def condition(self, block):        return not '\n' in block and len(block) <= 70 and not block[-1] == ':'

not ‘\n’ in block and len(block) <= 70 and not block[-1] == ‘:’条件,首先看第一个,由于这段文字只有一行,block中只保留了字符,不包含转义符,因此不包含’\n’,加之not,其布尔值为True,长度小于70,符和,最后一个字符不是冒号,也符合,因此返回True,即last = True,执行rule.action函数,因为从TitleRule中返回,type = ‘title’,查看TitleRule类中竟发现没有action函数,不用着急,原来是在父类中,即Rule类中。便执行handler.start、handler.feed、handler.end等函数,由于type为title,便执行start_title等函数,最终输出代码成这样:

<h1>Welcome to World Wide Spam, Inc.</h1>

说好的再举一个例子,便是列表中的第一句,如下:

- What is SPAM? (http://wwspam.fu/whatisspam)

首先是filter筛选器,发现里面的链接与正则表达式self.addFilter(r’(http://[.a-zA-Z/]+)’, ‘url’)相符,代入filter的函数种,那么pattern = r’(http://[.a-zA-Z/]+)’,name = ‘url’,这时handle.sub将会执行Handler类中的sub函数,如下:

    def sub(self, name):        def substitution(match):            result = self.callback('sub_', name, match)            if result is None:                result = match.group(0)            return result        return substitution

callback为回调函数,依据现有的局限理解,该函数将name加入到’sub_’中,接着将match作为参数投入到’sub_name’中,其中match为正则表达式所匹配的项—’http://wwspam.fu/whatisspam‘,具体是怎么与match连接上的,这暂且不大明白。这么看便是调用sub_url函数,如下:

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

会发现其实match.group(1) = match.group(0),因为正则表达式将引号内的所有内容都囊括到括号里了。这么返回值也可预见了,即result = <a href="http://wwspam.fu/whatisspam">http://wwspam.fu/whatisspam</a>,同样便一直返回上去,block里就根据匹配的内容进行修改,接下来进入第二个rule循环。
同样,首先是ListRule,ListRule.condition返回True,继续,执行ListRule.action,先判断if,inside = False,调看ListItemRule.condition,发现其符合block[0] == ‘-‘,返回True,那么if语句成立, 执行handler.start(self.type),type = ‘list’,根据第一个例子的过程可知会添加标签<ul>,同时inside改为True,返回False,那么last = False,进行下一个循环,判断ListItemRule,ListItemRule.condition返回真,执行ListItemRule.action,同样将添上<li>,返回True,last = True,跳出循环,进入下一block语句段。

研究琢磨了三天的时间,终究将这段代码研究到了一定程度,虽然说让我现在写出来仍有不少的困难,但总算是知道是怎么调用的,希望日后自己以此为模版,再进行模仿创作,写出自己的一段代码,无可否认,研究下来发现这段代码逻辑十分清晰,若需要使用于其他文档,只需要在相关部分进行修改即可,太厉害了,加油!

0 0
原创粉丝点击