【问题标题】:Extract PHP Code with Regular Expressions使用正则表达式提取 PHP 代码
【发布时间】:2013-08-25 16:47:40
【问题描述】:

我想用正则表达式提取本节的整个 PHP 代码:

<h1>Extract the PHP Code</h1>
    <?php
        echo(date("F j, Y, g:i a") . ' and a stumbling block: ?>');
        /* Another stumbling block ?> */
        echo(' that works.');
    ?>
<p>Some HTML text ...</p>

不幸的是,我的正则表达式卡在了绊脚石上:

/<[?]php[^?>]*[?]>/gim

有人提示如何捕获完整的 PHP 代码吗?

【问题讨论】:

  • 如果不熟悉正则表达式,请使用php.net/tokenizer
  • @Max你是在你的IDE/文件编辑器中执行这个操作,还是你打算执行php代码来修改你的php代码?

标签: php regex


【解决方案1】:

这样的事情可能会奏效

/<\?php.+?\?>$/ms

此模式使用两个flags

  • mPCRE_MULTILINE

    默认情况下,PCRE 将主题字符串视为由单个“行”字符组成(即使它实际上包含多个换行符)。 “行首”元字符 (^) 仅匹配字符串的开头,而“行尾”元字符 ($) 仅匹配字符串末尾或终止换行符之前(除非D 修饰符已设置)。这与 Perl 相同。设置此修饰符后,“行首”和“行尾”构造分别匹配主题字符串中任何换行符之后或之前的任何换行符,以及开头和结尾处。这相当于 Perl 的 /m 修饰符。如果主题字符串中没有 "\n" 字符,或者模式中没有出现 ^$,则设置此修饰符无效。

  • sPCRE_DOTALL

    如果设置了此修饰符,则模式中的点元字符匹配所有字符,包括换行符。没有它,换行符被排除在外。这个修饰符等价于 Perl 的 /s 修饰符。 [^a] 之类的否定类始终匹配换行符,与此修饰符的设置无关。

这是一对夫妇的样子


警告如果在行尾找不到?&gt;,则它不起作用。

所以它适用于

  • ?&gt;');
  • ?&gt; */

但它不适合

<?php
  echo "actual code";
  /*
   * comment ?>
   */
?>

简而言之,如果您的代码如此混乱,那么您需要一个更好的解决方案。如果您的代码是干净的,它应该可以正常工作。

【讨论】:

  • php 不需要标签闭包。
【解决方案2】:

你可以试试这个模式:

$pattern = <<<'LOD'
~

#definitions
(?(DEFINE)
    (?<sq> '(?:[^'\\]+|\\.)*+' ) # content inside simple quotes
    (?<dq> "(?:[^"\\]+|\\.)*+" ) # content inside double quotes
    (?<vn> [a-zA-Z_]\w*+ ) # variable name
    (?<hndoc> <<< (["']?) (\g<vn>) \g{-2} \R # content inside here/nowdoc
              (?: [^\r\n]+ | \R+ (?!\g{-1}; $) )*+
              \R \g{-1}; \R
    )
    (?<cmt> /\*                      # multiline comments
             (?> [^*]+ | \* (?!/) )*+
             \*/
    )
)

#pattern
<\?php \s+
(?: [^"'?/<]+ | \?+(?!>) | \g<sq> | \g<dq> | \g<hndoc> | \g<cmt> | [</]+ )*+
(?: \?> | \z )

~xsm
LOD;

测试:

$subject = <<<'LOD'
<h1>Extract the PHP Code</h1>
    <?php
        echo(date("F j, Y, g:i a") . ' and a stumbling block: ?>');
        /* Another stumbling block ?> */
        echo <<<'EOD'
    Youpi!!! ?>
EOD;
        echo(' that works.');
    ?>
<p>Some HTML text ...</p>
LOD;

preg_match_all($pattern, $subject, $matches);

print_r($matches);

另一种方式:

正如 mario 在评论中建议的那样,您可以使用分词器。这是最简单的方法,因为您不必定义任何内容,例如:

$tokens = token_get_all($subject);
$display = false;
foreach ($tokens as $token) {
    if (is_array($token)) {
        if ($token[0]==T_OPEN_TAG) $display = true;
        if ($display) echo $token[1];
        if ($token[0]==T_CLOSE_TAG) $display = false;
    } else {
        if ($display) echo $token;
    }
}

【讨论】:

  • @m.buettner: 单行 cmets 不会停止 ?&gt;
猜你喜欢
  • 1970-01-01
  • 2019-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
  • 1970-01-01
  • 2012-07-12
  • 1970-01-01
  • 2018-03-17
相关资源
最近更新 更多