PHP正则表达式 - 找不到特定标签之间的匹配项

时间:2018-06-13 21:59:21

标签: php regex

以下是我想用PHP正则表达式解析的字符串示例:

this is first %@ variable <bpt>inside tags %@ variable</bpt> trailing %@ variable

我需要匹配的是%@序列不在<bpt></bpt>之间。所以对于这个字符串模式应该返回2个匹配。

这是我到目前为止所做的:

%@(?!(?!<bpt).*\/bpt)

它没有按预期工作,只返回%@的最后一次出现。在正则表达式模式中,我想检查匹配后没有</bpt>结束标记,但是应该允许匹配后<bpt> ... </bpt>的情况。

Link to regex101.

2 个答案:

答案 0 :(得分:2)

你必须稍微改变你的正则表达式:

(?s)%@(?!(?:(?!<bpt>).)*<\/bpt>)

Live demo

故障:

(?s) # Enable DOTALL flag
%@ # Match `%@`
(?! # A negative lookahead that means preceding match
    # shouldn't come with next patterns which say:
    (?:(?!<bpt>).)* # Without matching `<bpt>`
    <\/bpt> # Match `</bpt>`
) # End of lookahead

但也有一种更优化的方法。由于正在使用PHP(PCRE),您可以使用名为SKIP的回溯动词:

<bpt>.*?<\/bpt>(*SKIP)(*F)|%@

Live demo

这样您就匹配整个bpt标记(asap),然后告诉引擎跳过并尝试其他路径。

答案 1 :(得分:1)

这是我的解决方案,查看评论以获取解释

$str="this is first %@ variable1 <bpt>inside tags %@ variable</bpt> trailing %@ variable2 %@";
//strip put all contents inside <bpt>
$content = preg_replace('/<bpt>[^<]+<\/bpt>/i', '', $str);
//split string to words 
$arr=explode(" ",$content);
//use array map for condition
//check for %@ and return preceding element after that 
$variable_only=array_map(function ($a,$k)use($arr) { if($a==='%@') {return isset($arr[$k+1]) ? $arr[$k+1] :'' ; } }, $arr,array_keys($arr));
//remove blank arrays and reset keys
$variable_only=array_values(array_filter($variable_only));
print_r($variable_only);

输出

Array ( [0] => variable1 [1] => variable2 )