什么reg表达模式我需要匹配{{和}}之间的所有内容

时间:2010-10-14 11:52:43

标签: php regex recursive-regex

我需要匹配{{和}}

之间的所有内容

我正在尝试解析维基百科,但是在运行rexex代码之后,我最终得到了orphan}}。这是我的PHP脚本。

<?php

$articleName='england';

$url = "http://en.wikipedia.org/wiki/Special:Export/" . $articleName;
ini_set('user_agent','custom agent'); //required so that Wikipedia allows our request.

$feed = file_get_contents($url);
$xml = new SimpleXmlElement($feed);

$wikicode = $xml->page->revision->text;



$wikicode=str_replace("[[", "", $wikicode);
$wikicode=str_replace("]]", "", $wikicode);
$wikicode=preg_replace('/\{\{([^}]*(?:\}[^}]+)*)\}\}/','',$wikicode);

print($wikicode);

?>

我认为问题是我嵌套{{和}}例如

{{something {{something else {{something new}} {{something old}} something blue}} something green}}

5 个答案:

答案 0 :(得分:4)

您可以使用:

\{\{(.*?)\}\}

大多数正则表达式都将大括号{视为文字字符,除非它是像{x,y}这样的重复运算符的一部分,而不是这里的情况。所以你不需要用反斜杠来逃避它,尽管这样做会得到相同的结果。

所以你也可以使用:

{{(.*?)}}

样品:

$ echo {{StackOverflow}} | perl -pe 's/{{(.*?)}}/$1/'
StackOverflow

另请注意,此处以非贪婪的方式使用匹配任何字符(除换行符之外)的.*。所以它会尝试尽可能少地匹配。

示例:

在字符串'{{stack}}{{overflow}}'中,它将匹配'stack'而不是'stack}}{{overflow'
如果您想要以后的行为,可以将.*?更改为.* ,使比赛贪婪。

答案 1 :(得分:2)

您的编辑显示您正在尝试进行递归匹配,这与原始问题非常不同。如果您不只是删除匹配的文本,我会建议您不要使用正则表达式,但这应该做你想要的:

$wikicode=preg_replace('~{{(?:(?:(?!{{|}}).)++|(?R))*+}}~s',
                       '', $wikicode);

在第一个{{与开始分隔符匹配后,(?:(?!{{|}}).)++会占用所有内容,直到下一个分隔符为止。如果它是另一个开放分隔符,(?R)将接管并以递归方式再次应用整个正则表达式。

(?R)和正则表达式功能一样非标准。它是PCRE库的独特之处,它支持PHP的正则表达式。其他一些风格有自己的匹配递归结构的方式,所有这些都非常不同。

答案 2 :(得分:0)

\{{2}(.*)\}{2}或更清洁,有外观(?<=\{{2}).*(?=\}{2}),但前提是您的正则表达式引擎支持它们。

如果您希望匹配在首次找到}}时停止(即非贪婪),则应将.*替换为.*?

此外,您应该考虑引擎的单行匹配设置,因为其中一些.默认情况下不会匹配换行符。您可以启用单行,也可以使用[.\r\n]*代替.*

答案 3 :(得分:0)

除了使用已经提到的非贪婪量词之外,您还可以使用:

\{\{(([^}]|}[^}])*)}}

内部([^}]|}[^}])*仅用于匹配零个或多个不包含序列}}的任意字符的序列。

答案 4 :(得分:0)

获得最短匹配的贪婪版本是

\{\{([^}]*(?:\}[^}]+)*)\}\}

(为了进行比较,使用字符串{{fd}sdfd}sf}x{dsf}},延迟版本\{\{(.*?)\}\}需要57步才能匹配,而我的版本只需要17步。这假设Regex Buddy的调试输出可以信任。 )