2012-04-23 45 views
1

我想从一个字符串从一个字符串中删除PHP标记与Python

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

删除PHP代码似乎工作的单行PHP标签OK,但是当一个PHP标签后关闭一些行,就不能抓住它。 任何人都可以帮忙吗?

+0

我认为这超出了正则表达式的能力,你需要一个实际的解析器。例如:'<?php echo''?>','<?php if(1):?> PHP ','<? echo'shorttags!'?>',''等 – 2012-04-23 21:20:45

+0

@FrancisAvila刚删除将完成我的工作! – wtayyeb 2012-04-23 21:39:37

+0

不,它不会。你认为它会,但它不会。试试这些测试用例的正则表达式。还要记住,你可以在php中省略最后的'?>'。 – 2012-04-23 21:44:35

回答

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) 

输出:

 
Simple: . 
Two on one line: (keep this) . 
Multiline: . 

我希望你不使用这种净化输入,因为这是不是为此目的不够好。 (这是一个黑名单,而不是一个白名单和黑名单是远远不够的。)

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

<?php echo '?>' ?> 

你仍然可以做它用正则表达式,但你不妨重新考虑你使用的是什么工具,因为正则表达式可能太复杂而无法阅读。下面的正则表达式将处理所有的弗朗西斯阿维拉的测试用例:

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编写的,这是一个从正则表达式创建分词器的常用工具。

我说“几乎”的原因是因为我们实际上使用扩展正则表达式。

+0

其在我的情况下工作,但没有're.DOTALL | re.MULTILINE' – wtayyeb 2012-04-24 02:18:45

+0

你是对的,都不是必需的。我正在玩正则表达式时忘了带出它们。 – 2012-04-24 03:58:54

-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' 
+0

以及如何将不需要的更改转换为\ n? – wtayyeb 2012-04-23 21:18:03

+0

你有权!您可以使用一种解决方案,将新行替换为不可能包含在文件中的“something”。然后运行正则表达式以过滤掉php标签。最后,用换行符替换'something'。 – 2012-04-23 21:32:37

+0

我很抱歉,但它删除了所有的字符串。它返回的字符串只包含一个\ n而没有其他字符,也许整个字符串都与第二行匹配。 – wtayyeb 2012-04-23 21:36:57

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的tokenizer来去除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); 
+0

我欣赏实际答案,旁边解释为什么正则表达式不足。尼斯。 – 2012-04-23 23:23:51

+0

我发布了一个处理所有测试用例的正则表达式。我怀疑像大多数标记器一样,PHP标记器首先建立在正则表达式上。通过使用PHP标记器,您可以省去编写正则表达式的工作,但实际上仍然使用正则表达式。 – 2012-04-23 23:26:36

+0

如果您好奇,可以阅读PHP在PHP源代码文件“Zend/zend_language_scanner.l”中使用的正则表达式。 – 2012-04-23 23:33:42

相关问题