繁体   English   中英

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

[英]PHP regex pattern match recursive

我在一个函数中具有此功能,该函数应该用括号内的内容替换任何括号序列,例如(abc)在任何递归出现的地方都变成abc ,因为可以嵌套括号。

$return =   preg_replace_callback(
    '|(\((.+)\))+|',
    function ($matches) {
        return $matches[2];
    },
    $s
);

当上面的正则表达式输入此字符串"a(bcdefghijkl(mno)p)q"作为输入时,它返回"ap)onm(lkjihgfedcbq" 。这表明该正则表达式已被匹配一次,我该怎么做才能使其继续匹配,甚至内部已经进行过匹配并生成此“ abcdefghijklmnopq”

以匹配均衡括号子则可以使用公知的\\((?:[^()]++|(?R))*\\)图案(在所描述的匹配平衡构建体 ),一个内部preg_replace_callback方法,其中,所述匹配值可以进一步处理(即使没有正则表达式,也可以从匹配中轻松删除所有()符号:

$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(((

参见PHP演示

要获得重叠的匹配项,您需要使用一种已知的技术,先于正向捕获,但是您将无法一次执行两项操作(替换和匹配),您可以先运行匹配项,然后替换:

$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) )

参见PHP演示

试试这个

  preg_match('/\((?:[^\(\)]*+|(?0))*\)/', $str )

https://regex101.com/r/NsQSla/1

只要它们是配对的,它将匹配( )内部的所有内容。

(abc) (abc (abc))

将有以下匹配

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

目前尚不清楚该算法的后置条件究竟是什么。 在我看来,您想删除匹配的( )对。 这里的假设是不匹配的括号单独留在家中(否则你只是去掉所有的( 'S和)的)。

所以我想这意味着输入字符串a(bcdefghijkl(mno)p)q变成abcdefghijklmnopq但是输入字符串a(bcdefghijkl(mno)pq变成a(bcdefghijklmnopq 。同样,输入字符串(a))会变成a)

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

我建议编写一个解析器以去除匹配的括号对。 不得不考虑无法匹配的作品会有些罗word:

<?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));

我知道这比正则表达式单行代码多得多,但是据我了解,它确实解决了问题。 我想知道是否有人可以使用正则表达式解决此问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM