想学习python已经很久了,以前使用ArcGIS的时候学习过一些简单的python语法,用来进行一些简单的GIS数据处理,但是后来并没有用到工作中也就荒废了,后来断断续续看过一些,最近想学习一门新的语言,就拿python下手了,仔细考(拼)虑(凑)出以下理由(喜欢就是喜欢,不用理由):

  • python强大库支持,在科学计算、人工智能等高精尖的领域使用甚广
  • 在运维中也算是除shell外的第二语言吧
  • 学习渗透测试的时候很多poc都是使用python写的,为了不仅仅停留在使用工具上,进一步学习
  • 在web中python也是快速开发的利器

本次学习主要是《python基础教程》第二版,简单回顾了前面几章基础知识后,开始拿后面的练习来学习,虽然代码大部分是直接参考书中源码,但是“纸上得来终觉浅,绝知此事要躬行”可不是废话,学习这件事不动手就是耍流氓,在自己动手编写书中例子的时候对python的语法和思想理解逐渐加深。先来一发


为了避免直接上代码略显突兀,显写出这个练习项目的思路:

先撇开具体实现,想想如果要实现将文本转化位html的做法:

  1. 文本一定时满足一定规则的
  2. 读取文本内容
  3. 根据预定义的规则分析读入的文本内容
  4. 符合某一种规则的文本加上对应的html标签
  5. 继续读入文本,回到2继续处理

再回来书中的项目,本项目共包含四个模块

  1. util.py:负责对文本进行一定的格式化,并读取文本
  2. rule.py:定义什么样的文本可以转化为什么样的html,两件事儿:
    1. 定义文本和html对应的规则
    2. 决定规则对应的处理程序(handler)
  3. handler.py:将给定规则的文本转换为html
  4. parse.py:调用util.py读取文本,调用rule.py判断文本对应的规则,调用handler处理给定规则的文本

这样子基本脉络已经清晰了,看代码

util.py

# -*- coding=utf-8 -*-

def lines(file):
'''
给每个段落强制添加一个空行
'''
for line in file :
yield line
yield '\n' def blocks(file):
'''
将输入的文件按按空行分块
'''
block = [] for line in lines(file):
if line.strip():
# line不是空行,属于一个块
block.append(line)
elif block:
# 当前行是空行,block不为空,块已经结束,返回块
yield ''.join(block).strip()
block = []

handler.py

# -*- coding=utf-8 -*-

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 subtitution(match):
result = self.callback('sub_', name, match)
if result is None:
match.group(0)
return subtitution class HTMLRender(Handler):
def start_document(self):
print '<html><head><title>...</title></head><body>'
def end_document(self):
print '</body>'
def start_paragraph(self):
print '<p>'
def end_paragraph(self):
print '</p>'
def start_head(self):
print '<h2>'
def end_head(self):
print '</h2>'
def start_title(self):
print '<h1>'
def end_title(self):
print '</h1>'
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 sub_em(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_email(self, match):
return '<a href="mailto:%s">%s</a>' % (match.group(1), match.group(1))
def feed(self, data):
print data

rule.py

# -*- coding=utf-8 -*-

class Rule:
def action(self, block, handler):
handler.start(self.type)
handler.feed(block)
handler.end(self.type)
return True class HeadRule(Rule):
'''
小标题的规则,没有换行符,长度小于70并且不以:结尾
''' type = 'head'
def condition(self, block):
return not '\n' in block and len(block) < 70 and block[-1] != ':'
class TitleRule(HeadRule):
'''
标题的规则,第一行是就是标题
'''
type = 'title'
first = True
def condition(self, block):
if not self.first:
return False
self.first = False
return HeadRule.condition(self, block)
class ListItemRule(Rule):
'''
li的规则,如果block以-开头就是listitem,在显示的时候去除-
''' 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):
'''
ul的规则,第一个li开始之前,添加ul,在第一个不是li的时候结束ul
'''
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)
# 每次返回False,在对block使用完本规则之后继续使用其他规则
return False class ParagraphRule(Rule):
'''
p段落规则,当前面所有的规则匹配的时候,默认使用本规则
''' type = 'paragraph'
def condition(self, block):
return True

parse.py

# -*- coding=utf-8
import re, sys
from util import *
from handler import *
from rule import *
import ipdb class Parser:
'''
解析器,利用rule对文本进行解析并转换为html,利用filter转换块内文本
''' 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):
#pdb.set_trace()
self.handler.start('document')
for block in blocks(file):
ipdb.set_trace()
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):
'''
基本文本解析器,只有h1,h2,p,ul,li,a,em,email
''' def __init__(self, handler):
Parser.__init__(self, handler)
self.addRule(ListRule())
self.addRule(ListItemRule())
self.addRule(TitleRule())
self.addRule(HeadRule())
self.addRule(ParagraphRule()) self.addFilter(r'\*(.+?)\*', 'em')
self.addFilter(r'(http://[\.a-zA-Z]+)', 'url')
self.addFilter(r'([\.a-zA-Z]+@[\.a-zA-Z]+[[a-zA-Z]+)', 'email') handler = HTMLRender()
parser = BasicTextParser(handler)
parser.parse(sys.stdin)

第一次练习就遇到这个项目显得略大,不过搞清楚思路之后整体把我就没问题了,在练习的过程中还遇到一些问题、学到一些东西,总结如下:

  • 子类调用父类的方法(包括__init__)

父类名.方法名(self, 参数)
A类调用B类方法
b = B()
b.方法(参数)

  • re模块的sub方法

re.sub(regex_str, replace_str, str)
将str中符合正则表达式regex_str的子串用replace_str代替
如果replace_str是正则表达式,可以使用分组替换,例如
re.sub(r'\*(.+)\*', r'---\1---', "asdasdasd*nskjdfnkjdsnf*sdfsdf")
re.sub(r'\*(.+)\*',lambda m: "---" + m.group(1) + "---" ,"asdasdasd*nskjdfnkjdsnf*sdfsdf")

其实作者里面有两个思想让我触动很深,甚是佩服:

  • 一个模块做最少的事,制作自己必须做的事
  • 事件的路由分发(借由python发挥的淋漓尽致)

这两种思想让项目整体架构变的很清晰,对扩展也很友好,大写的赞!


这个练习已经写完几天了,今天补上记录一下,代码位置

http://pan.baidu.com/s/1o7JVKKU

python练习一—文本转化渲染为html的更多相关文章

  1. 15.Python文本转化语音方法

    1.用pywin32模块来将文本转化为语音 通过pip install pywin32安装模块,pywin32是个万金油的模块,太多的场景使用到它,但在文本转语音上,它却是个青铜玩家,简单无脑但效果不 ...

  2. 【NLP】Python NLTK获取文本语料和词汇资源

    Python NLTK 获取文本语料和词汇资源 作者:白宁超 2016年11月7日13:15:24 摘要:NLTK是由宾夕法尼亚大学计算机和信息科学使用python语言实现的一种自然语言工具包,其收集 ...

  3. python Django教程 之模板渲染、循环、条件判断、常用的标签、过滤器

    python3.5 manage.py runserver python Django教程 之模板渲染.循环.条件判断.常用的标签.过滤器 一.Django模板渲染模板 1. 创建一个 zqxt_tm ...

  4. Python数据类型之“文本序列(Text Sequence)”

    Python中的文本序列类型 Python中的文本数据由str对象或字符串进行处理. 1.字符串 字符串是Unicode码值的不可变序列.字符串字面量有多种形式: 单引号:'允许嵌入"双&q ...

  5. Selenium2+python自动化23-富文本(自动发帖)

    前言 富文本编辑框是做web自动化最常见的场景,有很多小伙伴遇到了不知道无从下手,本篇以博客园的编辑器为例,解决如何定位富文本,输入文本内容 一.加载配置 1.打开博客园写随笔,首先需要登录,这里为了 ...

  6. python实现的文本编辑器 - Skycrab - 博客频道 - CSDN.NET

    Download Qt, the cross-platform application framework | Qt Project Qt 5.2.1 for Windows 64-bit (VS 2 ...

  7. 在微信小程序中使用富文本转化插件wxParse

    在微信小程序中我们往往需要展示一些丰富的页面内容,包括图片.文本等,基本上要求能够解析常规的HTML最好,由于微信的视图标签和HTML标签不一样,但是也有相对应的关系,因此有人把HTML转换做成了一个 ...

  8. Python处理json字符串转化为字典

    有一个需求,需要用python把json字符串转化为字典 inp_str = " {'k1':123, 'k2': '345','k3','ares'} " import json ...

  9. Python如何将整数转化成二进制字符串

    Python 如何将整数转化成二进制字符串 1.你可以自己写函数采用 %2 的方式来算. >>> binary = lambda n: '' if n==0 else binary( ...

随机推荐

  1. Python Day 12

    阅读目录: 内容回顾 函数默认值的细节 三元表达式 列表与字典推导式 函数对象 名称空间 函数嵌套的定义 作用域 ##内容回顾 # 字符串的比较 -- 按照从左往右比较每一个字符,通过字符对应的asc ...

  2. 移动端比较好用的滑动条 vue-slider-component

    安装: npm install vue-slider-component <template> <div> <vue-slider v-model="value ...

  3. Ubuntu搭建Anki服务器

    Ubuntu搭建Anki服务器 第一步安装Anki 阿里云的服务器,xshell远程登录上 #以root用户进行操作 #安装Akni服务 easy_install AnkiServer #添加名为an ...

  4. 第43章:MongoDB-集群--Sharding(分片)--多机的搭建

    ①环境准备 服务器规划 服务器[192.168.0.75] 服务器[192.168.0.84] 服务器[192.168.0.86] mongos mongos mongos config server ...

  5. dedecms mvc 开发

    目录结构说明: |_app    |___control      控制器(C)    |___model        模型(M)    |___templates    视图模板(V)    |_ ...

  6. Redis sentinel之集群搭建

    环境 由于不太熟悉docker,所以,把docker当虚拟机来用,服务器环境如下: Redis Server 环境搭建 Redis Server 01 搭建 并且制作Redis镜像 容器建立 # do ...

  7. 没有job offer,拿加拿大工签PGWP回国如何续签加拿大小签?

     很多同学因为在加拿大毕业后申请了三年的工作签证PGWP之后匆匆回国,没有来得及续签小签,但是回国一段时间之后又想要回加拿大,想要用自己的三年工签来续自己的小签.拿了加拿大PGWP没有job offe ...

  8. 解决Ubuntu自带编译器不好使问题

    解决Ubuntu自带编译器不好使问题 1.删除Ubuntu自带的tiny版本,这个版本用起来很别扭不好使. 2.安装full版本的vim 3.显示效果:full版本. 之前自带的版本:

  9. Android逆向之smali学习

    Smali是Android虚拟机Dalvik反汇编的结果. Dalvik指令集 指令格式为:[op]-[type](可选)/[位宽,默认4位] [目标寄存器],[源寄存器](可选) 赋值:move*  ...

  10. eclipse maven install 报错 jdk rather than jre?

    解决方案:window => Perference => java => install jre => 选中jre => edit => 选择文件夹为jdk的