美文网首页
Python 文本解析器

Python 文本解析器

作者: 海人为记 | 来源:发表于2018-02-23 12:49 被阅读549次

该文讲解一个使用Python来解析纯文本生成一个HTML页面的小程序。
详细教程及在线练习地址:Python - Python文本解析器

下面就开始实现解析器的步骤

  • 文本块生成器
    首先我们需要有一个文本块生成器把纯文本分成一个一个的文本块,以便接下来对每一个文本块进行解析,util.py代码如下:
#!/usr/bin/python
# encoding: 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():
            block.append(line)
        elif block:
            yield ''.join(block).strip()
            block = []

strip()函数可以去除一个字符串前后的空格以及换行符,如果在strip()函数添加不同的参数,如strip("me"),则可以去除字符串前后的"me"字符。

>>> s = "  This is me\n"
>>> s = s.strip()
>>> s
'This is me'
>>> s = s.strip("me")
>>> s
'This is '

yield()会返回一个生成器(generator)。如果对generator以及对yield语句不太熟悉,建议先阅读yield解释

  • 处理程序
    假设我们已经知道一个文本块是title/paragraph/heading/list,我们通过 handlers.py给他们打上合适的HTML标记,代码如下:
#!/usr/bin/python
# encoding: utf-8
# 为文本块打上合适的HTML标记

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 substitution(match):
            result = self.callback('sub_', name, match)
            if result is None: result = match.group(0)
            return result
        return substitution


class HTMLRenderer(Handler):
    """
    HTML 处理程序,给文本块加相应的 HTML 标记
    """
    def start_document(self):
        print('<html><head><title>ShiYanLou</title></head></body>')

    def end_document(self):
        print('</body></html>')

    def start_paragraph(self):
        print ('<p style= "color: #444;">')

    def end_paragraph(self):
        print('</p>')

    def start_heading(self):
        print('<h2 style="color: #68BE5D;">')

    def end_heading(self):
        print('</h2>')

    def start_list(self):
        print('<u1 style="color: #363736;">')

    def end_list(self):
        print('</u1>')

    def start_listitem(self):
        print('<li>')

    def end_listitem(self):
        print('</li>')

    def start_title(self):
        print('<h1 style="color: #1ABC9C;">')

    def end_title(self):
        print('</h1>')

    def sub_emphasis(self, match):
        return('<em>%s</em>' % match.group(1))

    def sub_url(self, match):
        return '<a target="_blank" style="text-decoration: none;color: #BC1A4B;" href="%s">%s</a>' % (match.group(1), match.group(1))

    def sub_mail(self, match):
        return '<a style="text-decoration: none;color: #BC1A4B;" href="mailto:%s">%s</a>' % (match.group(1), match.group(1))

    def feed(self, data):
        print(data)

在上面的代码中callable()函数能够检查一个函数是否能够被调用。如果能够被调用返回True。
gerattr()函数则是返回一个对象的属性值。举例来说,getattr(x,'foo',None)就相当于x.foo,而如果没有这个属性值foobar,则返回我们设定的默认值None。

  • 规则
    有了处理程序和文本块生成器,接下来就需要一定的规则来判断每个文本块交给处理程序将要加什么标记,rules.py代码如下:
#!/usr/bin/python
# encoding: utf-8
# 设计一定的规则来判断每个文本块交给处理程序将要加什么标记

class Rule:
    """
    规则父类
    """
    def action(self, block, handler):
        """
        加标记
        """
        handler.start(self.type)
        handler.feed(block)
        handler.end(self.type)
        return True

class HeadingRule(Rule):
    """
    一号标题规则
    """
    type = 'heading'
    def condition(self, block):
        """
        判断文本块是否符合规则
        """
        return not '\n' in block and len(block) <= 70 and not block[-1] == ':'

class TitleRule(HeadingRule):
    """
    二号标题规则
    """
    type = 'title'
    first = True

    def condition(self, block):
        if not self.first: return False
        self.first = False
        return HeadingRule.condition(self, block)

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

class ListRule(ListItemRule):
    """
    列表规则
    """
    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)
            self.inside = False
        return False

class ParagraphRule(Rule):
    """
    段落规则
    """
    type = 'paragraph'

    def condition(self, block):
        return True
  • 解析
    当我们知道每一个文本块进行怎么样的处理,交给谁去处理之后,我们就可以对整个文本进行解析了,markup.py代码如下:
#!/usr/bin/python
# encoding: utf-8
# 对整个文本进行解析的程序

import sys, re
from handlers import *
from util import *
from rules import *

class Parser:
    """
    解析器父类
    """
    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):
        """
        解析
        """
        self.handler.start('document')
        for block in blocks(file):
            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):
    """
    纯文本解析器
    """
    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]+[a-zA-Z]+)', 'mail')



"""
运行程序
"""
handler = HTMLRenderer()
parser = BasicTextParser(handler)
parser.parse(sys.stdin)
  • 运行与测试
    运行程序(纯文本文件为test.txt,生成HTML文件为test.html):
python3 markup.py <test.txt> test.html

获得test.html文件之后,我们想在浏览器中看一下我们的文本解释效果。
最简单的方法就是直接使用浏览器打开生成的test.html文件查看。

相关文章

  • Python 文本解析器

    该文讲解一个使用Python来解析纯文本生成一个HTML页面的小程序。详细教程及在线练习地址:Python - P...

  • Python 文本解析器

    一、项目介绍 本教程讲解一个使用 Python 来解析纯文本生成一个 HTML 页面的小程序。 二、相关技术 Py...

  • 2. Lexical analysis

    python程序被解析器读取,通过语法分析器解析为一系列token python的程序文本是用ASCII字符集的 ...

  • 和转义字符

    所有 XML 文档中的文本均会被解析器解析。只有 CDATA 区段(CDATA section)中的文本会被解析器...

  • 【Python】实验-文本解析器.1

    总步骤: 1.util.py:文本块生成器,把纯文本分成一个一个的文本块;2.handlers.py:为文本块打上...

  • Python实验二(补发)

    实验二:Python文本解析器 第一部分:错误总结 由于疏忽,在打代码的时候,没有对其中几个print加括号,导致...

  • Node.js字幕解析器,支持typescript,支持LRC、

    字幕解析器 简介 可以解析字幕文本的解析器 特性 你可以获得具体的秒和毫秒 它支持两种类型的文本:LRC、SRT ...

  • python网页解析器

    python 之网页解析器 一、什么是网页解析器 1、网页解析器名词解释 首先让我们来了解下,什么是网页解析器,简...

  • Python学习

    第二十七天 爬虫学习(二) 1、回顾 网页解析器python中常见的网页解析器:1、正则表达式2、python自带...

  • Django学习笔记

    1.从github上获取的项目需要配置python解析器,报错“Cannot find Python interp...

网友评论

      本文标题:Python 文本解析器

      本文链接:https://www.haomeiwen.com/subject/tljztftx.html