2

请帮忙,我的正则表达式技巧让我失望。我有以下字符串:

username|email_address|phone_numbers[number]profile[title|addresses[id]]

我希望能够提取方括号之间的任何数据,但不是该数据是已提取集合的子集的地方。所以任何嵌套都应该作为父级提取字符串的一部分。

在上面的例子中,我已经提取了两个部分:

"number"
"title|addresses[id]"

请注意如何不提取 [id],因为它是较低级别数据集的一部分。

我一直在尝试使用 preg_match 来做到这一点,但认为我可能不得不求助于迭代字符串中的每个字符。

4

3 回答 3

3

一个可悲的事实是正则表达式无法处理括号匹配,因为正则表达式没有记忆。(相当于DFA

要实现您想要的,您必须自己编写一个小型解析器(我认为),使用堆栈可以解决问题;)

使用堆栈解决问题的基本思想是.. 每次看到 [ 你都会推送堆栈,每次看到 ] 都会弹出堆栈并撤回自上次看到 [ 之后得到的字符串.

希望这可以帮助 ;)

于 2013-05-07T09:31:32.450 回答
3

这是一个正则表达式解决方案:

preg_match_all(
    '/(?<=\[)     # Assert that the previous characters is a [
      (?:         # Match either...
       [^[\]]*    # any number of characters except brackets
      |           # or
       \[         # an opening bracket
       (?R)       # containing a match of this very regex
       \]         # followed by a closing bracket
      )*          # Repeat as needed
      (?=\])      # Assert the next character is a ]/x', 
    $subject, $result, PREG_PATTERN_ORDER);
$result = $result[0];
于 2013-05-07T13:52:59.937 回答
1

我写了一个小解析器来达到预期的效果:

代码:

$data = 'username|email_address|phone_numbers[number]profile[title|addresses[id]wut]aaa[another test] aaand another one [which is [more] c[omplexer]t[h[an]] the others]';
print_r(parse($data));

function parse($string, $s1='[', $s2=']'){
    $c1 = $c2 = 0;$s = 1;
    $l = strlen($string);
    $array = array(array(), array());
    for($i=0;$i < $l;$i++){
        if($string[$i] == $s1){
            $c1++;
            $array[0][$c1] = $i;
        }elseif($string[$i] == $s2){
            $c2++;
            $array[1][$c2] = $i;
            if($c1 == $c2){
                $results[] = substr($string, $array[0][$s], $array[1][$c2] - $array[0][$s] + 1);
                $s=$c1+1;
            }
        }
    }
    return $results;
}

输出:

Array
(
    [0] => [number]
    [1] => [title|addresses[id]wut]
    [2] => [another test]
    [3] => [which is [more] c[omplexer]t[h[an]] the others]
)

在线演示

于 2013-05-07T13:37:07.897 回答