簡體   English   中英

使用正則表達式提取 PHP 代碼

[英]Extract PHP Code with Regular Expressions

我想用正則表達式提取本節的整個 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.+?\?>$/ms

正則表達式可視化

此模式使用兩個 標志

  • m表示PCRE_MULTILINE

    默認情況下,PCRE 將主題字符串視為由單個“行”字符組成(即使它實際上包含多個換行符)。 “行首”元字符 ( ^ ) 僅匹配字符串的開頭,而“行尾”元字符 ( $ ) 僅匹配字符串的末尾或終止換行符之前(除非設置了D修飾符)。 這與 Perl 相同。 設置此修飾符后,“行首”和“行尾”構造分別匹配主題字符串中任何換行符的緊隨其后或緊接其前的位置,以及開頭和結尾處。 這相當於 Perl 的/m修飾符。 如果主題字符串中沒有"\\n"字符,或者模式中沒有出現^$ ,則設置此修飾符無效。

  • s代表PCRE_DOTALL

    如果設置了此修飾符,則模式中的點元字符將匹配所有字符,包括換行符。 沒有它,換行符被排除在外。 此修飾符等效於 Perl 的/s修飾符。 否定類如[^a]始終匹配換行符,與此修飾符的設置無關。

這是幾場比賽的樣子

在此處輸入圖片說明


請注意,如果在行尾找不到?>則它不起作用。

所以它適用於

  • ?>');
  • ?> */

但它不會為

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

簡而言之,如果您的代碼如此混亂,您需要一個更好的解決方案。 如果您的代碼是干凈的,它應該可以正常工作。

你可以試試這個模式:

$pattern = <<<'LOD'
~

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM