【问题标题】:How to create loop with regular expression?如何使用正则表达式创建循环?
【发布时间】:2013-06-22 04:02:28
【问题描述】:

老实说,我想我应该先请你帮忙解决这个问题的语法。

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

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

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

所以每一个 {{START}} 都从内到外匹配它的 {{END}}!

如果我不能只用正则表达式来做到这一点。用 PHP 来做呢?

谢谢你。

【问题讨论】:

标签: php regex


【解决方案1】:

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

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

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

【讨论】:

  • PHP 使用了一个正则表达式引擎,它不仅可以使用正则表达式。 pcre.org/pcre.txt - 所以你的回答只是学术问题 - 不是实际问题。但是,您也可以使用该引擎来完成您的大纲。只是第一部分不适用于 PHP/PCRE。
【解决方案2】:

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

$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+}}(?&gt;[^{]++|(?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+}}))

这将匹配所有级别。

【讨论】:

    【解决方案3】:

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

    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}} 
    

    【讨论】:

    • OP 想要一个 PHP 解决方案。再试一次。
    • 添加了 PHP,不知道它是否正确。好几年没做PHP了。
    猜你喜欢
    • 2019-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多