我想编写一个简单的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)上运行它时,发生了错误。
请帮帮我。
答案 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>