正则表达式匹配一组字符,但仅限于特定字符未分组

时间:2014-02-03 03:42:03

标签: php regex preg-match-all preg-split

这是一个棘手的问题,我有一个字符串:

This is some text with a {%TAG IN IT%} and some more text then {%ANOTHER TAG%} with some more text at the end.

我有一个匹配标签的正则表达式:

({%\w+[\w =!:;,\.\$%"'#\?\-\+\{}]*%})

将匹配起始标记与任何字母数字字符,后跟任意数量的其他ansi字符(上述正则表达式中指定的样本集)。

但是(在PHP中使用“preg_match_all”“preg_split”至少)该集合同时包含百分比(%)和花括号({如果同一行上有两个标记,则表示正则表达式匹配太多。

例如,在给出的示例中,匹配以下内容:

{%TAG IN IT%} and some more text then {%ANOTHER TAG%}

如您所见,%} ... {%匹配。所以,我需要的是允许“%”但不是在“}”后面

我尝试过非reedy匹配和负向前瞻,但负向前瞻不会在字符集中起作用(即[\ w ...] *集中的所有内容)。

我被困住了!

2 个答案:

答案 0 :(得分:1)

您可以使用轮换来实现此目的:

/\{%(?:[^%]|%(?!}))*%\}/

匹配不是%的字符或未跟}的字符(使用前瞻assertion)。

$str = 'This is some text with a {%tag with % and } inside%} and some more text then {%ANOTHER TAG%} with some more text at the end.';

$pattern = '/\{%(?:[^%]|%(?!}))*%\}/';

preg_match_all($pattern, $str, $matches);
print_r($matches[0]);

输出:

Array
(
    [0] => {%tag with % and } inside%}
    [1] => {%ANOTHER TAG%}
)

答案 1 :(得分:0)

对正则表达式稍作修改(只需添加问号即可使其非贪婪) -

<?php
    $input = "This is some text with a {%TAG % }IT%%} and some more text then {%ANOTHER TAG%} with some more text at the end.";
    $regexp = "/{%\w+[\w =!:;,\.\$%\"'#\?\-\+\{}]*?%}/";
    //                                            ^ Notice this
    if(preg_match_all($regexp, $input, $matches, PREG_SET_ORDER)) {
        foreach($matches as $match) {
            var_dump($match);
            echo "\r\n";
        }
        unset($match);
    }
    /*
        Outputs:
        array
          0 => string '{%TAG % }IT%%}' (length=14)
        array
          0 => string '{%ANOTHER TAG%}' (length=15)
    */
?>