zoukankan      html  css  js  c++  java
  • python基础教程笔记—即时标记(详解)

      最近一直在学习python,语法部分差不多看完了,想写一写python基础教程后面的第一个项目。因为我在网上看到的别人的博客讲解都并不是特别详细,仅仅是贴一下代码,书上内容照搬一下,对于当时刚学习python的我帮助有限。

      下面是自己学习过程整理的一些内容。

      

    基础版:

      基础教程上面的项目例子,都会先出一个基础的代码版本,然后根据第一个版本,进行相应的补充完善。我们先来看一下util.py这个文件。

     1 #encoding:utf-8
     2 #生成器,for循环时会依次返回每一行,它只在文件的最后追加了一个空行
    
     3 def lines(file):
     4     for line in file:yield line
     5     yield '
    '
     6 #生成器,for循环时会依次返回文本块组成的函数
     7 def blocks(file):
     8     block = []
     9     for line in lines(file):
    10         if line.strip():
    11             block.append(line)
    12         elif block:
    13             yield ''.join(block).strip()
    14             block = []

    这里的两个主要内容是生成器和for...in语法。

    首先我们来看lines()方法,参数是文件,然后对文件进行循环,每次读取一行文件,主意这离的yield关键字,这里代表方法是一个生成器,循环的时候到yield我们可以理解成返回一次line内容。文本读完后,yield处是一个' '。

    blocks()方法就使用了上面的生成器,每次循环取出内容后,对line内容进行判断,如果有值,去除两边空格,添加到列表中,否则将block列表生成字符串。我们可以看出blocks也是一个生成器,他的实际功能是,从文件中,依次读取出来一个文本块。

      然后是simple_markup.py文件。

     1 import sys,re
     2 from util import *
     3 
     4 print '<html><head><title>hello</title></head><body>'
     5 
     6 title = True
     7 for block in blocks(sys.stdin):
     8     block = re.sub(r'*(.+?)*',r'<em>1</em>',block)
     9     if title:
    10         print '<h1>'
    11         print block
    12         print '</h1>'
    13         title = False
    14     else:
    15         print '<p>'
    16         print block
    17         print '</p>'
    18 print '</body></html>'
    这里我们需要注意一下,re.sub(r'*(.+?)*',r'<em>1</em>',block),他是re模块的应用,首先增则匹配到内容,然后替换式替换。
    其他部分,就是判断title是否为True,若是则给h1标签,否则给p标签。

    扩展版:
      在上面的文件中,功能基本实现,下面的内容是功能的复杂实现。我们接着往下看,首先是handlers.py文件。
      
     1 #encoding:utf-8
     2 class Handler:
     3     '调用方法的处理类'
     4 
     5     #判断当前类是否有对应的方法,所有的话则根据提供的额外参数使用对应方法
     6     def callback(self,prefix,name,*args):
     7         method = getattr(self,prefix+name,None)
     8         if callable(method):return method(*args)
     9     
    10     #callback的辅助方法,前缀就是start,只需要提供方法名即可
    11     def start(self,name):
    12         self.callback('start_',name)
    13     #前缀为end的callback辅助方法
    14     def end(self,name):
    15         self.callback('end_',name)
    16     
    17     #返回方法名subsutitution    
    18     def sub(self,name):
    19         def substitution(match):
    20             result = self.callback('sub_',name,match)
    21             if result is None: result = match.group(0)
    22             return result
    23         return substitution
    24 
    25 class HTMLRenderer(Handler):
    26     def start_document(self):
    27         print '<html><head><title>title</title></head><body>'
    28     def end_documrnt(self):    
    29         print '</body></html>'
    30     def start_paragraph(self):
    31         print '<p>'
    32     def end_paragraph(self):
    33                 print '</p>'
    34     def start_heading(self):
    35                 print '<h2>'
    36     def end_heading(self):
    37                 print '</h2>'
    38     def start_list(self):
    39                 print '<ul>'
    40     def end_list(self):
    41                 print '</ul>'
    42         def start_listitem(self):
    43                 print '<li>'
    44         def end_listitem(self):
    45                 print '</li>'
    46         def start_title(self):
    47                 print '<h1>'
    48         def end_title(self):
    49                 print '</h1>'
    50     def sub_emphasis(self,match):
    51         return '<em>%s</em>' % match.group(1)
    52     def sub_url(self,match):
    53         return '<a href="%s">%s</a>' % (match.group(1),match.group(1))
    54     def sub_mail(self,match):
    55         return '<a href="mailto:%s">%s</a>' % (match.group(1),match.group(1))
    56     def feed(self,data):
    57         print data

    先看Handler类,他有四个方法,其中重点是callback和sub。

    callback:两个必须参数,一个额外参数。

      getAttr()用来判断类中是否存在prefix+name的方法,若存在返回prefix+name,否则返回None。

      callable()用来判断方法是否可以调用,若可以调用,则给予参数*args并且调用,*args的含义是额外参数。

    start,end是包装了callback的两个方法,不细表。

    sub:

      目的是返回一个函数作为re.sub的替换函数,这样re.sub就不是写死的了。其中定义了一个substitution方法,实际上调用后返回的就是这个方法。他也就是我们后面re.sub中需要用到的替换函数。

      细心的朋友可能会注意到,这里有一个match参数,当时在这里我费解了很久,明明没有这个参数,可是之后的调用却确实使用到了,我打印这个参数,显示的是re对象。

      书上有这样一个小例子,

    1 from handlers import *
    2 handler = HTMLRenderer()
    3 import re
    4 print re.sub(r'*(.+?)*',handler.sub('emphasis'),'this *is* a test ')
    5 #输出为'This <em>is</em> a test'

         当时在这了我完全就懵逼了,因为handler.sub('emphasis')返回的明明是一个方法,但是他没有match参数啊。

      然后仔细看书,书上在前面有这样一句话,re.sub函数可以将第一个函数作为第二个参数。至少笔者觉得这句话写的很奇怪,’第一个函数‘明明要写成第一个参数啊有木有。好吧,不吐槽这些。

      大概意思就是,re.sub的第二个参数可以是一个函数作为替换式,替换式的参数就是re.sub的第一个参数匹配后返回的正则对象。

      这下就可以看懂了,我们会去调用sub_emphasis(self,match),然后match.group(1)表示的实际上是is。关于group(1)大家去看一下,re模块的内容,在这里我就直接告诉你他的内容,就是匹配式(.+?)中的内容。

      HTMLRenderer类继承了Handler类,其中主要定义了一些用来输出的方法,不细说。

      

      再来看rules.py文件。

     1 #encoding:utf-8
     2 class Rule:
     3     def action(self,block,handler):
     4         handler.start(self.type)
     5         handler.feed(block)
     6         handler.end(self.type)
     7         return True
     8 
     9 class HeadingRule(Rule):
    10     type = 'heading'
    11     #不包含
    ,也就是说并非最后一个块;长度小于70;不以冒号结尾
    12     def condition(self,block):
    13         return not '
    ' in block and len(block) <=70 and not block[-1] == ':'
    14 
    15 class TitleRule(HeadingRule):
    16     type = 'title'
    17     #只工作一次,处理第一个快,因为处理完一次之后first的值被设置为了False,所以不会再执行处理方法了
    18     first = True
    19     def condition(self,block):
    20         if not self.first: return False
    21         self.first = False
    22         return HeadingRule.condition(self,block)
    23 
    24 class ListItemRule(Rule):
    25     type = 'listitem'
    26     def condition(self,block):
    27         return block[0] == '-'
    28     def action(self,block,handler):
    29         handler.start(self.type)
    30         handler.feed(block[1:].strip())
    31         handler.end(self.type)
    32         return True
    33 
    34 class ListRule(ListItemRule):
    35     type = 'list'
    36     inside = False
    37     def condition(self,block):
    38         return True
    39     def action(self,block,handler):
    40         if not self.inside and ListItemRule.condition(self,block):
    41             handler.start(self.type)
    42             self.inside = True
    43         elif self.inside and not ListItemRule.condition(self,block):
    44             handler.end(self.type)
    45             self.inside = False
    46         return False
    47 
    48 class ParagraphRule(Rule):
    49     type = 'paragraph'
    50     def condition(self,block):
    51         return True

       这里比较简单,我们先看看基类Rule,定义了两个方法,condition和action.

      condition接受一个文本块作为参数,通过返回布尔值来表示文本块是否适合当前的规则。

      action接受文本块和处理程序对象作为参数,用来对文本块执行操作,进行输出。

      集成的类都不复杂,这里单独说一下ListRule。

      这里定义了一个变量inside为True,我们可以理解这个变量的意思是—List列表开始。因为在html中List中还会包含节点,也就是这里的ListItem,所以他会在遇到一个列表项的时候触发一次,然后在最后一个列表项的时候再次触发。所以inside作为一个标志位,用来进行判断符合规则的文本块时需要执行start还是end方法。

      最后一个文件,markup.py

     1 #encoding:utf-8
     2 import sys,re
     3 from handlers import *
     4 from util import *
     5 from rules import *
     6 
     7 class Parser:
     8     #初始化一些属性
     9     def __init__(self,handler):
    10         self.handler = handler
    11         self.rules = []
    12         self.filters = []
    13     #向规则列表中添加规则
    14     def addRule(self,rule):
    15         self.rules.append(rule)
    16     #向过滤器列表中添加过滤器
    17     def addFilter(self,pattern,name):
    18         #创建过滤器,实际上这里return的是一个替换式
    19         def filter(block,handler):
    20             return re.sub(pattern,handler.sub(name),block)
    21         self.filters.append(filter)
    22     #对文件进行处理
    23     def parse(self,file):
    24         self.handler.start('document')
    25         #对文件中的文本块依次执行过滤器和规则    
    26         for block in blocks(file):
    27             for filter in self.filters:
    28                 block = filter(block,self.handler)
    29             for rule in self.rules:
    30                 #判断文本块是否符合相应规则,若符合做执行规则对应的处理方法
    31                 if rule.condition(block):
    32                     last = rule.action(block,self.handler)
    33                     if last:break
    34         self.handler.end('document')
    35 
    36 class BasicTextParser(Parser):
    37     def __init__(self,handler):
    38         Parser.__init__(self,handler)
    39         self.addRule(ListRule())
    40         self.addRule(ListItemRule())
    41         self.addRule(TitleRule())
    42         self.addRule(HeadingRule())
    43         self.addRule(ParagraphRule())
    44 
    45         self.addFilter(r'*(.+?)*','emphasis')
    46         self.addFilter(r'(http://[.a-zA-Z/]+)','url')
    47         self.addFilter(r'([.a-zA-Z]+@[.a-zA-Z]+[a-zA-Z]+)','mail')
    48         
    49 handler = HTMLRenderer()
    50 parser = BasicTextParser(handler)
    51 
    52 parser.parse(sys.stdin)
    53         

      同样先看基类Parser,构造函数需要一个handler对象作为参数,以供全局调用,同时初始化了两个列表。

      addRule和addFilter的目的是向规则和过滤器列表添加元素。

      parse方法,读取文本文件,循环出每一个文本块,先通过过滤器过滤,然后执行相应规则。

      我们注意,规则和按照列表依次执行的,他会判断返回值,若为False则不再对文本块执行后续规则了。

      BasicTextParser类,的构造函数只是在基类的基础上增加了,向规则和过滤器列表添加具体内容的步骤。

      

      然后初始化类,并且对文件执行parse方法,即时标记项目完成。

    后记:

      学习完python语法后,真正动手做的第一个项目,对初学者还是有一点难度的,尤其是整体细节上。

      后续会依次写完其他几个项目的学习笔记。欢迎喜欢的朋友关注,bye!

  • 相关阅读:
    包含游标、数组的例子
    团队开发的注意点
    养成逻辑的习惯
    C# DEV 右键出现菜单
    C#中ToString数据类型格式大全 千分符(转)
    Oracle系统查询的语句
    PLSQLDevelop 查询当前未完成的会话
    Oracle 异常工作中出现的
    Oracle 返回结果集 sys_refcursor
    DevExpress.XtraEditors.TextEdit,设定为必须number类型的。
  • 原文地址:https://www.cnblogs.com/isuifeng/p/5839748.html
Copyright © 2011-2022 走看看