制作降价解析器时的正则表达式问题

时间:2012-11-13 13:41:53

标签: python regex markdown

我正在尝试在python中创建一个markdown解析器,不是因为它很有用,而是因为它很有趣,因为我正在尝试学习正则表达式。

#! /usr/bin/env python
#-*- coding: utf-8 -*-

import re

class Converter:

    def markdown2html(self, string):

        string = re.sub('\*{3}(.+)\*{3}', '<strong>\\1</strong>', string)
        string = re.sub('\*{2}(.+)\*{2}', '<i>\\1</i>', string)
        string = re.sub('^#{1}(.+)$', '<h1>\\1</h1>', string, flags=re.MULTILINE)
        string = re.sub('^#{2}(.+)$', '<h2>\\1</h2>', string, flags=re.MULTILINE)

        return string

markdown_sting = """
##h2 heading
#H1 heading
This should be a ***bold*** char
#anohter h1
anohter ***bold***
this is a **italic** string
"""

converter = Converter()
print converter.markdown2html(markdown_sting)

打印

<h1>#h2 heading</h1>
<h1>H1 heading</h1>
This should be a <strong>bold</strong> char
<h1>anohter h1</h1>
anohter <strong>bold</strong>
this is a <i>italic</i> string

正如您所看到的,它不会解析h2标记。哪里出错了?

4 个答案:

答案 0 :(得分:4)

当解析器看到#时,它会替换h1。然后它尝试替换h2,但是没有字符串##,因为在解析'#'部分时已经替换了其中一个哈希值(h1)。 / p>

一个简单的解决方法是交换订单:

string = re.sub('^#{2}(.+)$', '<h2>\\1</h2>', string, flags=re.MULTILINE)
string = re.sub('^#{1}(.+)$', '<h1>\\1</h1>', string, flags=re.MULTILINE)

通常,当您将变换应用于数据时,您应该从限制性最强的进行排序,以避免出现这些问题。

答案 1 :(得分:4)

通过确保标题文本的第一个字符不是哈希符号,您可以确保仅匹配所需的哈希符号数。这可以通过使用[^#]这样完成:

string = re.sub('^#{1}([^#].*)$', '<h1>\\1</h1>', string, flags=re.MULTILINE)
string = re.sub('^#{2}([^#].*)$', '<h2>\\1</h2>', string, flags=re.MULTILINE)

这样,规则的顺序无关紧要,使规则更加健壮。

答案 2 :(得分:1)

按顺序评估这些正则表达式。 h1正则表达式将抓取以#开头的任何行并将其转换为<h1>。因此,当它到达h2正则表达式时,该行不再以##开头。交换这两个表达式。

答案 3 :(得分:1)

更合适,更有效的方法可能是比较字符串的第一个字符,然后执行简单的字符串替换

def markdown2html(self, string):

    if string[0:2] == "##":
        string = string.replace( "##", "<h2>" ) + "</h2>"
    if string[0] == "#":
        string = string.replace( "##", "<h1>" ) + "</h1>"
    return string

这样你就可以进行简单的列表操作而不是RegEx。但在所有情况下,订单都很重要