在python中,如何使用正则表达式提取字符串?

时间:2017-07-05 15:11:07

标签: python regex

我想编写一个简单的markdown解析器函数,它将采用单行markdown并转换为适当的HTML。为了简单起见,我想在atx语法中仅支持markdown的一个功能:headers。

标题由(1-6)哈希表示,后跟空格,后跟文本。哈希数决定了HTML输出的标题级别。 的实施例

# Header will become <h1>Header</h1>

## Header will become <h2>Header</h2>

###### Header will become <h6>Header</h6>

规则如下

标题内容应仅在初始#标签加空格字符之后。

无效的标题应该只是作为收到的降价返回,无需翻译。

结果输出中应忽略标题内容和主题标签之前和之后的空格。

这是我制作的代码。

import re
def markdown_parser(markdown):
    results =''
    pattern = re.compile("#+\s")
    matches = pattern.search(markdown.strip())
    if (matches != None):
        tag = matches[0]
        hashTagLen = len(tag) - 1
        htmlTag = "h" + str(hashTagLen)
        content = markdown.strip()[(hashTagLen + 1):]
        results = "<" + htmlTag + ">" + content + "</" + htmlTag + ">"
    else:
        results = markdown
    return results

当我运行此代码时,异常发生如下。

  

未处理的例外:&#39; _sre.SRE_Match&#39;对象不可订阅

我不确定为什么会发生此错误。

当我在shell上运行脚本时,它运行良好。 但是当我在unittest环境(import unittest)上运行它时,发生了错误。

请帮帮我。

3 个答案:

答案 0 :(得分:1)

该代码看起来非常冗长,并且可以在正则表达式中执行许多逻辑。

如果你看一下用perl编写的原始markdown库,你可以看到只需要一个模式,然后,从第一个捕获组,你可以获得它的样式。

The original implementation is here

sub _DoHeaders {
my $text = shift;

# Setext-style headers:
#     Header 1
#     ========
#  
#     Header 2
#     --------
#
$text =~ s{ ^(.+)[ \t]*\n=+[ \t]*\n+ }{
    "<h1>"  .  _RunSpanGamut($1)  .  "</h1>\n\n";
}egmx;

$text =~ s{ ^(.+)[ \t]*\n-+[ \t]*\n+ }{
    "<h2>"  .  _RunSpanGamut($1)  .  "</h2>\n\n";
}egmx;


# atx-style headers:
#   # Header 1
#   ## Header 2
#   ## Header 2 with closing hashes ##
#   ...
#   ###### Header 6
#
$text =~ s{
        ^(\#{1,6})  # $1 = string of #'s
        [ \t]*
        (.+?)       # $2 = Header text
        [ \t]*
        \#*         # optional closing #'s (not counted)
        \n+
    }{
        my $h_level = length($1);
        "<h$h_level>"  .  _RunSpanGamut($2)  .  "</h$h_level>\n\n";
    }egmx;

return $text;

}

除非由于某种原因你不能,否则最好使用降价库,因为这是原始库,疣和所有的实现。

您可以看到Markdown-Python库如何实现它here

class HashHeaderProcessor(BlockProcessor):
""" Process Hash Headers. """

# Detect a header at start of any line in block
RE = re.compile(r'(^|\n)(?P<level>#{1,6})(?P<header>.*?)#*(\n|$)')

def test(self, parent, block):
    return bool(self.RE.search(block))

def run(self, parent, blocks):
    block = blocks.pop(0)
    m = self.RE.search(block)
    if m:
        before = block[:m.start()]  # All lines before header
        after = block[m.end():]     # All lines after header
        if before:
            # As the header was not the first line of the block and the
            # lines before the header must be parsed first,
            # recursively parse this lines as a block.
            self.parser.parseBlocks(parent, [before])
        # Create header using named groups from RE
        h = util.etree.SubElement(parent, 'h%d' % len(m.group('level')))
        h.text = m.group('header').strip()
        if after:
            # Insert remaining lines as first block for future parsing.
            blocks.insert(0, after)
    else:  # pragma: no cover
        # This should never happen, but just in case...
        logger.warn("We've got a problem header: %r" % block)

答案 1 :(得分:0)

您不使用索引来访问匹配对象。 https://docs.python.org/2/library/re.html#match-objects

答案 2 :(得分:0)

您可以使用re.sub将一个替换为6 #,然后使用您想要的html替换空格和单词(模式为(#{1,6}) (\w+))。

re.sub可以与函数一起使用来处理替换。

import re

def replacer(m):
    return '<h{level}>{header}</h{level}>'.format(level=len(m.group(1)), header=m.group(2))

def markdown_parser(markdown):
    results = [re.sub(r'(#{1,6}) (\w+)', replacer, line) for line in markdown.split('\n')]
    return "\n".join(results).strip()

sourceText = "##header#content## smaller header#contents### something"
print(markdown_parser(sourceText))

打印##header#content<h2>smaller</h2> header#contents<h3>something</h3>