有没有办法在正则表达式中以任何顺序匹配一组组?

时间:2010-08-30 01:28:30

标签: c# python regex

我查看了相关的问题,有很多,但我认为没有人回答这个问题。我对Regex很新,但我想要变得更好,所以请耐心等待。我试图匹配字符串中的几个组,但任何顺序。这是我应该使用正则表达式的东西吗?如果是这样,怎么样?如果重要,我打算在IronPython中使用它们。

编辑:有人让我更具体,所以在这里:

我想将re.match与正则表达式一起使用:

\[image\s*(?(@alt:(?<alt>.*?);).*(@title:(?<title>.*?);))*.*\](?<arg>.*?)\[\/image\]

但它只会在命名组处于正确顺序时匹配,并用空格分隔。我希望能够以任何顺序匹配命名组,只要它们出现在正则表达式中的位置。

将应用于此的典型字符串可能如下所示:

[image @alt:alien; @title:reddit alien;]http://www.reddit.com/alien.png[/image]

但我应该没有问题匹配:

[image @title:reddit alien; @alt:alien;]http://www.reddit.com/alien.png[/image]

所以'属性'(第一个'标签'中'@'和';'之间的东西)应该以任何顺序匹配,只要它们都出现。

2 个答案:

答案 0 :(得分:2)

标题中问题的答案是“否” - 要按任意顺序匹配N组,正则表达式应该具有“或”(正则表达式中的|特征) N!(N阶乘)可能的组排列,从1到N的所有整数的乘积。这是一个快速增长非常的数字 - 对于N只等于6,它已经是720 ,对于7,它几乎是5000,依此类似于令人眼花缭乱的速度 - 所以这种方法对任何不是很小的N来说都是不切实际的。

解决方案可能很多,具体取决于您希望与哪些组分开。比如说,你不关心(如果你关心,用更好的规格编辑你的问题)。

在这种情况下,如果重叠匹配不可能或者你没问题,那么制作N个单独的正则表达式,每个组一个 - 比如这些N个编译的RE对象都在名为grps的列表中,然后

mos = [g.search(thestring) for g in grps]

是组的匹配对象列表(None表示组不匹配)。使用mos列表,您可以执行各种检查和/或进一步操作,例如all(mos)True当且仅当所有组都匹配时,{{1} }是已匹配的子字符串列表,依此类推。

如果你需要非重叠匹配,那就有点复杂了 - 你可以为每个组提取所有可能匹配的边界,然后看看是否有办法从这些[m.group() for m in mos]列表中提取一组N个区间,每个列表一个,这样它们中没有两个是成对交叉的。这是一个有点微妙的算法(如果你想要一个大N的合理速度,当然),所以我认为它值得一个单独的问题,并且无论如何在这个问题上是否值得讨论它是否需要取决于您未指定的令人难以置信的许多因素。

因此,请首先使用更精确的规范编辑您的问题,然后可以澄清一些事项,以便为您提供所需的代码和/或算法。

编辑:我看到OP现在至少在提供示例的范围内澄清了这个问题 - 尽管令人困惑的是,他提供了一个RE模式示例和一个应该不匹配,无论顺序如何(RE指定存在子串N,示例字符串有 - 令人费解!)。

无论如何,如果示例中的组数(两个似乎可以互换,一个似乎必须出现在特定位置)代表OP的实际问题,那么感兴趣的排列总数是只有两个,所以加入“只有两个”排列与垂直条@title当然是非常可行的。这是OP的真正问题,但是......?

编辑:如果感兴趣的排列数很少,这里是避免模式中重复组名称问题的一种方法示例(语法需要Python 2.7或更高版本,但这只是对于最终的“字典理解” - 许多以前版本的Python都提供相同的功能,只是使用不太优雅的|语法; - )......:

dict(('a', ...

答案 1 :(得分:0)

这与使用正则表达式解析HTML的关键问题非常类似 - 不要求始终以相同的顺序指定属性,并且许多标记具有令人惊讶的属性(如<br clear="all">。所以看来你正在使用非常相似的标记语法。

Pyparsing以间接方式解决此问题 - 而不是尝试解析所有不同的排列,解析常规“@attrname:attribute value;”语法,并跟踪属性映射数据结构中的属性键和值。通过映射可以轻松获取“title”属性,无论它是在图像标记中的第一个还是最后一个。此行为内置于pyparsing API方法,makeHTMLTags和makeXMLTags。

当然,这个标记是不是 XML,但类似的方法可以很容易地使用结果:

text = """[image @alt:alien; @title:reddit alien;]http://www.reddit.com/alien1.png[/image]

But I should have no problem matching:

[image @title:reddit alien; @alt:alien;]http://www.reddit.com/alien2.png[/image]
"""

from pyparsing import Suppress, Group, Word, alphas, SkipTo, Dict, ZeroOrMore

LBRACK,RBRACK,COLON,SEMI,AT = map(Suppress,"[]:;@")
tagAttribute = Group(AT + Word(alphas) + COLON + SkipTo(SEMI) + SEMI)
imageTag = LBRACK + "image" + Dict(ZeroOrMore(tagAttribute)) + RBRACK
imageLink = imageTag + SkipTo("[/image]")("text")

for taginfo in imageLink.searchString(text):
    print taginfo.alt
    print taginfo.title
    print taginfo.text
    print

打印:

alien
reddit alien
http://www.reddit.com/alien1.png

alien
reddit alien
http://www.reddit.com/alien2.png