zoukankan      html  css  js  c++  java
  • python练习一—文本转化渲染为html

    想学习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 '
    '
    
    
    def blocks(file):
        '''
        将输入的文件按按空行分块
        '''
        block = []
    
        for line in lines(file):
            if line.strip():
                # line不是空行,属于一个块
                block.append(line)
            elif block:
                # 当前行是空行,block不为空,块已经结束,返回块
                yield ''.join(block).strip()
                block = []
    View Code

    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
    View Code

    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 '
    ' 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
    View Code

    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)
    View Code

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

    • 子类调用父类的方法(包括__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

  • 相关阅读:
    WebService基于SoapHeader实现安全认证
    js中SetInterval与setTimeout用法
    Fiddler 教程
    jQuery 的 serializeArray()、serialize() 方法
    Javascript中Array.prototype.map()详解
    MS DOS 命令大全
    Chrome的JS调试工具
    jquery插件之DataTables 参数介绍
    C#中的Params、ref、out的区别
    C#记录日志、获取枚举值 等通用函数列表
  • 原文地址:https://www.cnblogs.com/sunshine-2015/p/5468265.html
Copyright © 2011-2022 走看看