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)

输出:

简单的: 。
二合一:(保留这个)。
多行:.

我希望您没有使用它来清理输入,因为这不足以达到此目的。(这是黑名单,不是白名单,黑名单永远不够。)

如果要处理复杂的情况,例如:

<?php echo '?>' ?>

您仍然可以使用正则表达式来做到这一点,但您可能希望重新考虑您使用的工具,因为正则表达式可能太复杂而无法阅读。以下正则表达式将处理 Francis Avila 的所有测试用例:

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 回答