PHP正则表达式捕获代码

时间:2011-06-18 18:06:21

标签: php regex

我一直在尝试以与wiki标签类似的方式捕获代码块:

{{code:
      code goes here
   }}

示例代码如下所示,

$strings = array('AbCd1zyZ9', 'foo!#$bar');
foreach ($strings as $testcase) {
    if (ctype_alnum($testcase)) {
        echo "It is The string $testcase consists of all letters or digits.\n";
    } else {
        echo "The string $testcase does not consist of all letters or digits.\n";
    }
}

基本上我想捕捉{{..}}之间的任何东西。 HTML页面中嵌入了多个这样的块。

我将不胜感激。

3 个答案:

答案 0 :(得分:5)

首先,正则表达式不是解决此问题的好方法。正确的方法是编写一个理解语言语义的解析器,并梳理出细微之处。话虽如此,如果你仍然需要快速而肮脏的基于正则表达式的方法,它将在99.99%的时间内工作但有几个已确认的错误(请参阅答案结束),请点击此处:

您可以使用preg_match_all()。这是一个概念证明:

$input = "
<html>
    <head>
        <title>{{code:echo 'Hello World';}}</title>
    </head>
    <body>
        <h1>{{code:\$strings = array('AbCd1zyZ9', 'foo!#$bar');
foreach (\$strings as \$testcase) {
    if (ctype_alnum(\$testcase)) {
        echo \"It is The string \$testcase consists of all letters or digits.\\n\";
    } else {
        echo \"The string $testcase does not consist of all letters or digits.\\n\";
    }
}
}}</h1>
    </body>
</html>
";

$matches = array();
preg_match_all('/{{code:([^\x00]*?)}}/', $input, $matches);

print_r($matches[1]);

输出以下内容:

Array
(
    [0] => echo 'Hello World';
    [1] => $strings = array('AbCd1zyZ9', 'foo!#');
foreach ($strings as $testcase) {
    if (ctype_alnum($testcase)) {
        echo "It is The string $testcase consists of all letters or digits.\n";
    } else {
        echo "The string  does not consist of all letters or digits.\n";
    }
}

)

小心点。有一些边缘案例错误涉及在“代码”块中遇到}}提前终止:

  1. 如果}}出现在带引号的字符串中,则正则表达式过早匹配
  2. 如果}是“代码”区块的最后一个字符,并且紧跟}},则会丢失代码块中的结束}

答案 1 :(得分:2)

正如我在评论中所说,Asaph's answer是一个很好的可靠正则表达式,但在代码块中包含}}时会崩溃。希望这不会是一个问题,但是因为它有可能,所以最好让你的正则表达式更加广泛。如果我们可以假设在两个单引号之间出现的任何}}都不表示代码的结尾,就像在Asaph的<div>{{code:$myvar = '}}';}}</div>示例中那样,我们可以扩展我的正则表达式:

{{code:((?:[^']*?'[^']*?')*?[^']*?)}}

[^']*?'查找一组非'字符,后跟单引号,[^']*?'[^']*?'连续查找其中两个字符。像“{1}}这样”吞下“字符串。我们lazily查找任意数量的这些字符串,然后查找包含'}}'的任何非字符串代码的其余部分,最后查找结尾[^']*?

这使我们可以匹配整个字符串}},而不仅仅是{{code:$myvar = '}}';}}

然而,这种方法仍然存在问题。在字符串中转义引号(例如在{{code:$myvar = '}}中)将无法正常工作,因为我们将首先“吞下”{{code:$myvar = '\'}}\'';}},然后立即以'\'结束。也可以确定这些转义的单引号,或者添加对双引号字符串的支持,但是你需要问自己在什么时候使用代码解析器更好。

查看整个正则表达式here。 (如果最初没有匹配任何内容,只需单击窗口即可。)


  

我如何使用结果来说出位置   它在新的}}

使用替换功能:

<div>

preg_replace($expression, "<div>$0</div>", $input) 会插入整个匹配项,并将其放在新的$0块之间。或者,如果您只想要实际的源代码,请使用<div>,因为我们在单独的捕获组中捕获了源代码。

再次,请参阅替换here


我在兔子洞深处走了......

$1

这不会破坏转义的单引号,并且正确匹配{{code:((?:(?:[^']|\\')*?(?<!\\)'(?:[^']|\\')*?(?<!\\)')*?(?:[^']|\\')*?)}}

Ta-da

答案 2 :(得分:0)

使用

preg_match_all("/{{(.)*}}/", $text, $match)

其中text是可能包含代码的文本 这会捕获{{ }}

之间的任何内容