-1

我想用 Python 来处理 wikitext!

比如原文:

== 123 ==
=== 1234 ===

到:

<h2> 123 </h2>
<h3> 1234 </h3>

怎么做!我需要正则表达式吗?它会起作用吗?

import re
block_head = r"""
(?P<head>
    ^
    \s*
    (?P<head_head> =+ )
    \s*
    (?P<head_text> .*? )
    \s*
    (?P=head_head)
    \s*
    $
  )
"""
while 1:
somestring=raw_input()
dict1=re.search(block_head,somestring, re.X).groupdict()
if(dict1['head_head']=='======'):
    print '<h6>'+dict1['head_text']+'</h6>'
if(dict1['head_head']=='====='):
    print '<h5>'+dict1['head_text']+'</h5>'
if(dict1['head_head']=='===='):
    print '<h4>'+dict1['head_text']+'</h4>'

我想知道如何解决这个问题:

abc'''123'''aa

abc<b>123</b>aa
4

3 回答 3

2

是的,您可能想要使用正则表达式。

不过,您可能希望避免重新发明轮子。MoinMoin python wiki 平台已经实现了各种格式处理程序,包括一个确实使用正则表达式来解析输入文本的 Media Wiki 格式处理程序

为了借鉴该实现,它使用正则表达式:

block_head = r"""
    (?P<head>
        ^
        \s*
        (?P<head_head> =+ )
        \s*
        (?P<head_text> .*? )
        \s*
        (?P=head_head)
        \s*
        $
    )
"""

匹配包含 1 个或多个=字符的行,后跟文本,后跟相同数量的=字符。这使用带有re.X标志的详细正则表达式语法(忽略空格)。

使用该正则表达式,您可以匹配标题并通过计算=字符数来计算它们的“级别”:

>>> re.search(block_head, '=== Some header! ===', re.X).groupdict()
{'head_text': 'Some header!', 'head': '=== Some header! ===', 'head_head': '==='}

非详细版本将是:

block_head = r"(?P<head>^\s*(?P<head_head>=+)\s*(?P<head_text>.*?)\s*(?P=head_head)\s*$)"

以此为起点(仔细阅读re模块文档,直到您了解每个部分的作用),然后从那里扩展。

于 2013-03-10T14:39:02.983 回答
0

当您尝试实现自己的时,请在 PyPi 上查看Python 中的 Markdown模块作为参考。运行sudo pip install markdown然后导航到您的 Python 安装目录/lib/python.version/site-packages/markdown以获取已构建和安装的包,或者您可以从上面的链接下载存档并浏览原始源。那里有很多,但是您应该能够找到一些很好的例子来说明您正在尝试做的事情。

于 2013-03-10T14:56:10.583 回答
0
import re

reg = re.compile('^(={1,3})(.+?)\\1 *\r?$',re.MULTILINE)

s = '''== B123 ==
=== Z1234 ==='''

def ripl(m, d = {'=':'h1','==':'h2','===':'h3'}):
    return '<{0:s}>{1:s}</{0:s}>'.format(d[m.group(1)],m.group(2))

print reg.sub(ripl,s)

正则表达式模式的解释:

^没有re.MULTILINE标志将意味着“字符串的开始”。
^withre.MULTILINE表示“一行或字符串的开头”。

(={1,3})是一个捕获组,组 1。
它捕获 1 到 3 个字符=,但由于该组前面是,因此它仅在一行的开头 ^捕获这些= 。

(.+?)是捕获组号 2.
.+?捕获所有类型的字符(除了\n,因为没有 re.DOTALL 标志的点不匹配\n
如果它是(.+)only ,那将是贪婪的,也就是说它会去尽可能:好吧,在目前的情况下,由于点不匹配\n,它会一直到行尾,即直到\n前面的位置,第二组将赶上第二个系列======也是我们不想要的。
但是?after要求.+这个表达.+不贪心,也就是说,一旦它碰到后面指定的东西,就在某处停下来.+?

因此,\\1 *\r?$定义前面.+?将停止的字符组。从这个角度来看,和)之间的括号无关紧要。 它的意思是 : .+?\\1 *\r?$

  • 1) 与行前相同的字符组,必须被第 1 组捕获,表示为\\1
  • 2)然后可能是一系列空白(没用但这个地方可能有一些)
  • 3)然后可能\r,但不是强制性的。我放这个是因为在 Windows 上,行尾是\r\n
  • 4) 最后,$表示“一行或字符串的结尾”,因为 re.MULTILINE 改变其含义与 for^

我用这个条件\\1 *\r?$断言将匹配的系列======将是最后一个。因为,.+?据说这部分会在它遇到的第一个部分停止。什么,当第一个不是最后一个时?对于这种情况,我们必须规定,.+?仅当同一组位于行尾时,才能在与组 1 相同的组前面停止:所以这使得 charachters =出现在行中的可能性(实际上我不知道在wiki上是否可以,但我想到了这个案例)

.

注意
要排除以下情况

===abcd=====
======ijk==

被转化为

<h3>abcd==</h3>
<h2>====ijk</h2>

模式必须是'^(={1,3}(?!=))(.+?)(?<!=)\\1 *\r?$'

该部分的(?!=)意思是'就在字符串中连续1到3个字符=停止的这个位置之后,必须没有另一个= '

该部分的(?<!=)意思是'就在字符串中最后一个连续 1 到 3 个字符=开始的位置的前面,必须没有另一个= '

于 2013-03-10T15:34:04.853 回答