Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP正则表达式模式匹配递归_Php_Regex_Pcre - Fatal编程技术网

PHP正则表达式模式匹配递归

PHP正则表达式模式匹配递归,php,regex,pcre,Php,Regex,Pcre,我在一个函数中有这样一个函数,它应该用它所包含的内容替换任何括号序列,就像abc变成abc,在任何地方它甚至递归出现,因为paren可以嵌套 $return = preg_replace_callback( '|(\((.+)\))+|', function ($matches) { return $matches[2]; }, $s ); 当输入上述正则表达式时,该字符串返回aponmlkjihgfedcbq。这表明正则表达式只匹配一次。我

我在一个函数中有这样一个函数,它应该用它所包含的内容替换任何括号序列,就像abc变成abc,在任何地方它甚至递归出现,因为paren可以嵌套

$return =   preg_replace_callback(
    '|(\((.+)\))+|',
    function ($matches) {
        return $matches[2];
    },
    $s
);
当输入上述正则表达式时,该字符串返回aponmlkjihgfedcbq。这表明正则表达式只匹配一次。我该怎么做才能让它继续匹配,即使是在已经匹配的内部,并生成这个“abcdefghijklmnopq”

试试这个

  preg_match('/\((?:[^\(\)]*+|(?0))*\)/', $str )
只要它们是配对的,它就会匹配内部的所有内容

范例

(abc) (abc (abc))
将有以下匹配项

Match 1
   Full match   0-5 `(abc)`
Match 2
   Full match   6-17    `(abc (abc))`

目前还不清楚该算法的后置条件究竟是什么。在我看来,你是想把配对的衣服脱掉。这里的假设是,不匹配的括号是单独存在的,否则您只需去掉所有的“和”

所以我猜这意味着输入字符串abcdefghijklmnopq变成了abcdefghijklmnopq,但是输入字符串abcdefghijklmnopq变成了abcdefghijklmnopq。同样,输入字符串a将变成a

使用pcre可以做到这一点,因为它确实提供了一些非常规功能,但我对此表示怀疑。输入字符串的语言不规则;它与上下文无关。@ArtisticPhoenix的答案是匹配匹配括号的完整对。它没有做的是匹配所有嵌套对。在我对语言理论的拙劣理解中,这种嵌套匹配本质上是不规则的

我建议编写一个解析器来去掉匹配的括号对。必须考虑不匹配的产品,这有点冗长:

<?php

// Parse the punctuator sub-expression (i.e. anything within ( ... ) ).
function parse_punc(array $tokens,&$iter) {
    if (!isset($tokens[$iter])) {
        return;
    }

    $inner = parse_punc_seq($tokens,$iter);
    if (!isset($tokens[$iter]) || $tokens[$iter] != ')') {
        // Leave unmatched open parentheses alone.
        $inner = "($inner";
    }

    $iter += 1;
    return $inner;
}

// Parse a sequence (inside punctuators).
function parse_punc_seq(array $tokens,&$iter) {
    if (!isset($tokens[$iter])) {
        return;
    }

    $tok = $tokens[$iter];
    if ($tok == ')') {
        return;
    }
    $iter += 1;

    if ($tok == '(') {
        $tok = parse_punc($tokens,$iter);
    }

    $tok .= parse_punc_seq($tokens,$iter);
    return $tok;
}

// Parse a sequence (outside punctuators).
function parse_seq(array $tokens,&$iter) {
    if (!isset($tokens[$iter])) {
        return;
    }

    $tok = $tokens[$iter++];
    if ($tok == '(') {
        $tok = parse_punc($tokens,$iter);
    }

    $tok .= parse_seq($tokens,$iter);
    return $tok;
}

// Wrapper for parser.
function parse(array $tokens) {
    $iter = 0;
    return strval(parse_seq($tokens,$iter));
}

// Grab input from stdin and run it through the parser.
$str = trim(stream_get_contents(STDIN));
$tokens = preg_split('/([\(\)])/',$str,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
var_dump(parse($tokens));

我知道这比正则表达式一行程序要多得多,但据我所知,它确实解决了这个问题。我很想知道是否有人能用正则表达式解决这个问题。

要匹配平衡插入式子字符串,您可以在方法内部使用中描述的一种众所周知的模式,其中可以进一步操纵匹配值,只需从匹配中删除所有和符号,即使没有正则表达式也很容易做到:

$re = '/\((?:[^()]++|(?R))*\)/';
$str = 'a(bcdefghijkl(mno)p)q((('; // Added three ( at the end
$result = preg_replace_callback($re, function($m) {
    return str_replace(array('(',')'), '', $m[0]);
}, $str);
echo $result; // => abcdefghijklmnopq(((

要获得重叠匹配,您需要使用已知技术,在正向前瞻中捕获,但您无法同时执行两个操作替换和匹配,您可以先运行匹配,然后再替换:

$re = '/(?=(\((?:[^()]++|(?1))*\)))/';
$str = 'a(bcdefghijkl(mno)p)q(((';
preg_match_all($re, $str, $m);
print_r($m[1]);
// => Array ( [0] => (bcdefghijkl(mno)p)  [1] => (mno) )

请参阅。

/\?:[^\]*+|?0*\/this@ArtisticPhoenixParen可以出现在主题字符串中的任何位置,而不仅仅是stingAnd的开头?这与此无关。请看,[^的用法不表示,也不同于^[这意味着字符串的开始。请告诉我这怎么不能回答这个问题,它甚至是递归出现的,因为paren可以嵌套。请澄清它如何回答这一部分…用它所包含的内容替换任何括号序列,如abc变为abcit,解决它们被卡住的部分…关系可以简单到str_replace[,],$match[1]在验证后,它们是一对匹配的括号。这实际上取决于它们的用例,处理匹配的最佳方法是什么。然后,您需要在解决方案中添加此额外步骤。您是否可以在已进行的匹配中使其匹配,以便Match3=abcyour模式接近。但不匹配内部匹配,如使用abcdefghijklmnopq i进行fedt输出bcdefghijklmnop,并粘贴一个代码副本,显示mno从未匹配。@cholthipaultiopic:Look,.Ok,我的坏。我运行了错误的模式。还有一件事。如何获得递归产生的匹配。@cholthipaultiopic:不知道递归产生的匹配是什么意思。abcdefghijklmnopq中唯一的匹配是bcdefghijklmnop,并且它位于$m[0]中。只需将它添加到一个数组中,您可以使用&$arr将其传递给匿名方法。请参阅。我最初真正想做的是匹配平衡括号中的任何内容,如abcdefghijklmnopq,应该将bcdefghijklmnop和mno作为匹配项。