1

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

我正在尝试解析维基百科,但在运行 rexex 代码后,我以孤儿 }} 告终。这是我的 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);

?>

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

{{ 东西 {{ 其他东西 {{ 新东西 }}{{ 旧东西 }} 蓝色的东西 }} 绿色的东西 }}

4

5 回答 5

4

您可以使用:

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

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

所以你也可以使用:

{{(.*?)}}

样本:

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

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

例子:

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

于 2010-10-14T11:54:44.980 回答
2

您的编辑表明您正在尝试进行递归匹配,这与原始问题非常不同。如果您不只是删除匹配的文本,我建议您根本不要使用正则表达式,但这应该可以满足您的要求:

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

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

(?R)与正则表达式功能一样非标准。它是 PCRE 库所独有的,它为 PHP 的正则表达式提供了动力。其他一些风格有自己的匹配递归结构的方式,它们都彼此非常不同。

于 2010-10-14T18:38:09.323 回答
0

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

如果您希望您的匹配在第一次找到时停止}}(即非贪婪),您应该替换.*.*?.

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

于 2010-10-14T12:00:16.600 回答
0

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

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

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

于 2010-10-14T12:10:19.333 回答
0

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

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

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

于 2010-10-14T12:10:22.813 回答