5

老实说,我认为我应该首先就这个问题的语法寻求您的帮助。

但是,如果您能理解我的意思,请用合适的标题编辑标题。

有没有办法制作可以像这样分割文本的模式。

{{START}}
    {{START}}
        {{START}}
            {{START}}
            {{END}}
        {{END}}
    {{END}}
{{END}}

因此,每个 {{START}} 都从内到外匹配其 {{END}}!

如果我不能只用正则表达式做到这一点。使用 PHP 来做这件事怎么样?

先谢谢你了。

4

3 回答 3

4

这超出了正则表达式的能力,它只能解析正则语法。您所描述的将需要下推自动机(常规语言由常规自动机定义)。

您可以使用正则表达式来解析各个元素,但是“深度”部分需要由具有内存概念的语言处理(PHP 可以)。

因此,在您的解决方案中,正则表达式将仅用于识别您的标签,而跟踪深度和确定 END 标签属于哪个元素的真正逻辑必须是您的程序本身。

于 2013-06-22T04:18:58.800 回答
3

有可能的!您可以使用递归正则表达式来获得每个级别的内容:

$data = <<<LOD
{{START1}}
    aaaaa
    {{START2}}
        bbbbb
        {{START3}}
            ccccc
            {{START4}}
                ddddd
            {{END4}}
        {{END3}}
    {{END2}}
{{END1}}
LOD;

$pattern = '~(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}}))~';
preg_match_all ($pattern, $data, $matches);

print_r($matches);

解释:

部分:({{START\d+}}(?>[^{]++|(?1))*{{END\d+}})

这部分模式描述了一个嵌套结构,其中{{START#}}{{END#}}

(             # open the first capturing group
{{START\d+}}  
(?>           # open an atomic group (= backtracks forbidden)
    [^{]++    # all that is not a { one or more times (possessive)
  |           # OR
    (?1)      # refer to the first capturing group itself
)             # close the atomic group
{END\d+}}     # 
)             # close the first capturing group

现在的问题是你不能只用这部分捕获所有级别,因为字符串的所有字符都被模式消耗掉了。换句话说,您无法匹配字符串的重叠部分。

问题是将所有这部分包装在一个零宽度断言中,该断言不消耗像前瞻这样的字符(?=...),结果:

(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}}))

这将匹配所有级别。

于 2013-06-22T04:56:16.297 回答
1

你不能用纯正则表达式来做到这一点,但是可以通过一个简单的循环来完成。

JS 示例:

//[.\s\S]* ensures line breaks are matched (dotall not supported in JS)
var exp = /\{\{START\}\}([.\s\S]*)\{\{END\}\}/;

var myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}";

var matches = [];
var m = exp.exec(myString);
while ( m != null ) {
    matches.push(m[0]);
    m = exp.exec(m[1]);
}

alert(matches.join("\n\n"));

PHP(我不知道这是否正确,自从我完成 PHP 以来一直如此)

$pattern = "/\{\{START\}\}([.\s\S]*)\{\{END\}\}/";
$myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}";

$result = preg_match($pattern, $myString, $matches, PREG_OFFSET_CAPTURE);
$outMatches = array();
while ( $result ) {
    array_push($outMatches, $matches[0]);
    $result = preg_match($pattern, $matches[1], $matches, PREG_OFFSET_CAPTURE);
}
print($outMatches);

输出:

{{START}}
test
{{START}}
test 2
{{START}}
test 3
{{START}}
test4
{{END}}
{{END}}
{{END}}
{{END}}

{{START}}
test 2
{{START}}
test 3
{{START}}
test4
{{END}}
{{END}}
{{END}}

{{START}}
test 3
{{START}}
test4
{{END}}
{{END}}

{{START}}
test4
{{END}} 
于 2013-06-22T04:46:42.417 回答