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

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

  

基础版:

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

  1. #encoding:utf-8
  2. #生成器,for循环时会依次返回每一行,它只在文件的最后追加了一个空行\n
  3. def lines(file):
  4. for line in file:yield line
  5. yield '\n'
  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处是一个'\n'。

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>'
  1. 这里我们需要注意一下,re.sub(r'\*(.+?)\*',r'<em>\1</em>',block),他是re模块的应用,首先增则匹配到内容,然后替换式替换。
    其他部分,就是判断title是否为True,若是则给h1标签,否则给p标签。
  2.  
  3. 扩展版:
      在上面的文件中,功能基本实现,下面的内容是功能的复杂实现。我们接着往下看,首先是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. #不包含\n,也就是说并非最后一个块;长度小于70;不以冒号结尾
  12. def condition(self,block):
  13. return not '\n' 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)

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

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

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

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

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

  

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

后记:

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

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

python基础教程笔记—即时标记(详解)的更多相关文章

  1. Python基础教程,流程控制语句详解

    1.程序结构 计算机在解决问题时,分别是顺序执行所有语句.选择执行部分语句.循环执行部分语句,分别是:顺序结构.选择结构.循环结构.如下图: 很多人学习python,不知道从何学起.很多人学习pyth ...

  2. python基础教程笔记—画幅好画(详解)

    今天写一下基础教程里面的第二个项目,主要使用python来做一个pdf的图,比较简单. 首先我们需要安装用到的模块pip install reportlab即可. 书上是用urlopen从往上下了一个 ...

  3. Python基础数据类型-函数传参详解

    Python基础数据类型-函数传参详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.位置参数 #!/usr/bin/env python #_*_coding:utf-8_* ...

  4. python基础教程笔记 第1单元 && 第2单元

    1.http://docs.python.org/dev/3.0/whatsnew/3.0.htmlpython-announce-listpython-help2.交互式编译器3.非整数除法 .1. ...

  5. Python基础教程笔记 第二章

    本章的名字虽然叫列表和元组,但是本章讲的最多的是列表,元祖指讲了很少的一部分.因为元组和列表很多方面都是一样的. 列表和元组的区别:列表可以被修改,元祖不可以被修改. python包含的6种内建序列: ...

  6. Python基础教程笔记 第一章

    /  表示整除,当导入_future_模块中的version时,/ 表示正常的的除法, 此时可用//表示整除,不论数字是整型还是浮点型,都可以用//表示整除. ** 表示幂次方  例如 2**3    ...

  7. Python基础教程笔记——第7章:更加抽象(类)

    下面进入Python的面向对象: 对象的魔力: 多态:---可以对不同类的对象使用同样的操作 封装:---对外部隐藏对象内部的工作方式 继承:---以普通的类为基础建立专门的类对象 (1)多态: is ...

  8. Python基础教程笔记——第5章:条件,循环和其他语句

    5.1 print和import的更多信息 1. print()3.0之后print不再是语句,而是函数, >>> print('udg',12,13)   udg 12 13 &g ...

  9. Python基础教程笔记——第4章:字典

    字典 字典是Python唯一内建的数学映射类型,字典中的值没有特殊的顺序,键可以是数字,字符串,甚至是元组 字典的创建: 字典由键值对构成,字典中键是唯一的,而值不唯一.>>> a_ ...

随机推荐

  1. Java设计模式15:常用设计模式之享元模式(结构型模式)

    1. Java之享元模式(Flyweight Pattern) (1)概述:       享元模式是对象池的一种实现,英文名为"Flyweight",代表轻量级的意思.享元模式用来 ...

  2. tlb转dll

    项目中需要用到c++编写的dll文件,但是同事发给我的是一个tlb后缀的文件,此时需要用到vs命令工具,具体操作如下: 开始-->vs2010-->vs命令提示(2010) ,打开后,输入 ...

  3. Lamp下安装memcached

    1.先安装 libevent,再安装 Memcached主程序 # tar xf libevent-2.0.21-stable.tar.gz # cd libevent-2.0.21-stable # ...

  4. saltstack实战4--综合练习2

    Saltstack配置管理-功能模块-安装haproxy 配置管理,我们分了3层 最底层是系统初始化部分 倒数二层是功能模块,就是具体的产品的安装了 假如你的环境需要nginx,php,memcach ...

  5. Sharepoint2010之父子表实现

    在Sharepoint的实际运用中会经常使用到父子表来建立2个表之间的关系.通常父表为表头,存储公共的数据项目,子表存储细分的项目. 例如通过下面2个表实现图书借阅功能,表1为图书的基础信息,表2为图 ...

  6. 微信小程序(原名微信应用号)开发工具0.9版安装教程

    微信小程序全称微信公众平台·小程序,原名微信公众平台·应用号(简称微信应用号) 声明 微信小程序开发工具类似于一个轻量级的IDE集成开发环境,目前仅开放给了少部分受微信官方邀请的人士(据说仅200个名 ...

  7. 编写SASS的一些技巧

    更好的为变量命名 变量是Sass中最简单的特性之一,但有时候也会使用不当.创建站点范围内有语义化的变量,是不可或缺的工作.如果命名不好,他会变得难以理解和重复使用. 这里有一些命名变量的小技巧,提供参 ...

  8. Java解析XMl文件之SAX和DOm方法

    如题,这两种方法的jar包都在jdk中,不需要下载. 先来说下目录结构: 首先建一个Peron类封装person.xml的属性:DomParseService和SaxParseService分别为两种 ...

  9. 在c#中使用log4net

    1.从log4net官网下载最新的log4net.dll 2.设置配置文件在app.config <?xml version="1.0"?> <configura ...

  10. AppScan安全问题解决方案

    一. 环境准备 测试通常给的是PDF文档,动辄几百页,看起来很费劲,看文档的时间可能比解决问题的时间还长...所以作为需要解决问题的我们来说,最好安装AppScan,请测试人员提供类型为AppScan ...