1

文字列からphpタグを削除したい

content = re.sub('<\?php(.*)\?>', '', content)

単一行のphpタグでは問題なく動作するようですが、phpタグが後にいくつかの行を閉じると、それをキャッチできません。誰か助けてもらえますか?

4

3 に答える 3

2

この問題は正規表現では解決できません。文字列からPHPを解析するには、少なくとも少しのPHPを理解する実際のパーサーが必要です。

ただし、PHPを使用できる場合は、この問題を非常に簡単に解決できます。最後にPHPソリューション。

これは、正規表現のアプローチでうまくいかない可能性のあるいくつかの方法のデモンストレーションです。

import re

testcases = {
    'easy':("""show this<?php echo 'NOT THIS'?>""",'show this'),
    'multiple tags':("""<?php echo 'NOT THIS';?>show this, even though it's conditional<?php echo 'NOT THIS'?>""","show this, even though it's conditional"),
    'omitted ?>':("""show this <?php echo 'NOT THIS';""", 'show this '),
    'nested string':("""show this <?php echo '<?php echo "NOT THIS" ?>'?> show this""",'show this  show this'),
    'shorttags':("""show this <? echo 'NOT THIS SHORTTAG!'?> show this""",'show this  show this'),
    'echotags':("""<?php $TEST = "NOT THIS"?>show this <?=$TEST?> show this""",'show this  show this'),
}

testfailstr = """
FAILED: %s
IN:     %s
EXPECT: %s
GOT:    %s
"""

removephp = re.compile(r'(?s)<\?php.*\?>')

for testname, (in_, expect) in testcases.items():
    got = removephp.sub('',in_)
    if expect!=got:
        print testfailstr % tuple(map(repr, (testname, in_, expect, got)))

すべてのテストケースに合格する正規表現を取得することは不可能ではないにしても、非常に難しいことに注意してください。

PHPを利用できる場合は、PHPのトークナイザーを使用してPHPを取り除くことができます。 次のコードは、すべてのPHPコードを文字列から確実に削除し、すべての奇妙なコーナーケースもカバーする必要があります。

// one-character token, always code
define('T_ONECHAR_TOKEN', 'T_ONECHAR_TOKEN');

function strip_php($input) {
    $tokens = token_get_all($input);

    $output = '';
    $inphp = False;
    foreach ($tokens as $token) {
        if (is_string($token)) {
            $token = array(T_ONECHAR_TOKEN, $token);
        }
        list($id, $str) = $token;
        if (!$inphp) {
            if ($id===T_OPEN_TAG or $id==T_OPEN_TAG_WITH_ECHO) {
                $inphp = True;
            } else {
                $output .= $str;
            }
        } else {
            if ($id===T_CLOSE_TAG) {
                $inphp = False;
            }
        }
    }

    return $output;
}

$test = 'a <?php //NOT THIS?>show this<?php //NOT THIS';


echo strip_php($test);
于 2012-04-23T22:54:44.873 に答える
1

単純なケースを処理したいだけの場合は、単純な正規表現で問題なく機能します。*?Python正規表現の演算子は、最小限の一致を示します。

import re

_PHP_TAG = re.compile(r'<\?php.*?\?>', re.DOTALL)
def strip_php(content):
    return _PHP_TAG.sub('', content)

INPUT = """
Simple: <?php echo $a ?>.
Two on one line: <?php echo $a ?>, <?php echo $b ?>.
Multiline: <?php 
    if ($a) {
        echo $b;
    }
?>.
"""

print strip_php(INPUT)

出力:

単純: 。
1行に2つ:(これを保持)。
マルチライン:。

これはその目的には十分ではないため、入力をサニタイズするためにこれを使用していないことを願っています。(これはホワイトリストではなくブラックリストであり、ブラックリストだけでは十分ではありません。)

次のような複雑なケースを処理する場合:

<?php echo '?>' ?>

正規表現を使用してそれを行うことはできますが、正規表現は複雑すぎて読み取れない可能性があるため、使用しているツールを再検討することをお勧めします。次の正規表現は、FrancisAvilaのすべてのテストケースを処理します。

dstr = r'"(?:[^"\\]|\\.)*"'
sstr = r"'(?:[^'\\]|\\.)*'"
_PHP_TAG = re.compile(
    r'''<\?[^"']*?(?:(?:%s|%s)[^"']*?)*(?:\?>|$)''' % (dstr, sstr)
)
def strip_php(content):
    return _PHP_TAG.sub('', content)

正規表現は、この問題を解決するのにほぼ十分強力です。これを知っている理由は、PHPが正規表現を使用してPHPソースコードをトークン化するためです。PHPが使用する正規表現をで読むことができますZend/zend_language_scanner.l。これは、正規表現からトークナイザーを作成する一般的なツールであるLex用に作成されています。

私が「ほぼ」と言う理由は、実際に拡張正規表現を使用しているためです。

于 2012-04-23T23:13:51.963 に答える
-1

あなたはこれを通してそれをすることができます:

content = re.sub('\n','', content)
content = re.sub('<\?php(.*)\?>', '', content)

OPのコメントの後に更新された回答:

content = re.sub('\n',' {NEWLINE} ', content)
content = re.sub('<\?php(.*)\?>', '', content)
content = re.sub(' {NEWLINE} ','\n', content)

ipython

In [81]: content
Out[81]: ' 11111  <?php 222\n\n?> \n22222\nasd  <?php asd\nasdasd\n?>\n3333\n'

In [82]: content = re.sub('\n',' {NEWLINE} ', content)
In [83]: content
Out[83]: ' 11111  <?php 222 {NEWLINE}  {NEWLINE} ?>  {NEWLINE} 22222 {NEWLINE} asd  <?php asd {NEWLINE} asdasd {NEWLINE} ?> {NEWLINE} 3333 {NEWLINE} '

In [84]: content = re.sub('<\?php(.*)\?>', '', content)
In [85]: content
Out[85]: ' 11111   {NEWLINE} 3333 {NEWLINE} '

In [88]: content = re.sub(' {NEWLINE} ','\n', content)
In [89]: content
Out[89]: ' 11111  \n3333\n'
于 2012-04-23T21:12:07.797 に答える