正则表达式找到块之间的模式

时间:2018-01-19 05:57:11

标签: php regex pcre templating

我正在使用PHP构建一个模板引擎(类似于Django),用{ "AAL": { "station_code":"AAL", "id": "32313", "airport_name": "Aalborg", "latitude": "57.1", "longitude": "9.85", "timezone": "2", "dst_indicator": "E", "city": "Aalborg", "country": "Denmark", "country_code": "DK", "region": "TC1", "listing_display": "true", "pseudonyms": "" }, "AAR": { "station_code":"AAR", "id": "32314", "airport_name": "Tirstrup", "latitude": "56.15", "longitude": "10.2167", "timezone": "2", "dst_indicator": "E", "city": "Aarhus", "country": "Denmark", "country_code": "DK", "region": "TC1", "listing_display": "true", "pseudonyms": "" } } 替换其相关数据之间的所有内容。现在我能够做到这一点,但我面临的情况是只需要在块之间进行替换,例如{{ }}循环块,并忽略不在它们之间的所有括号。

我能够在this regex101 example中获得一些结果但只得到每个块的第一个{% for y in x %}。我想要做的是匹配每个块中的所有{{ }},不包括外面的那些。

1 个答案:

答案 0 :(得分:2)

出于学习目的(非常好!),您有几种可能性:

  1. 多步骤方法(更易于理解和维护):

  2. 整体正则表达式解决方案(更复杂,可能更多"花式")

  3. <小时/> 广告1)

    使用以下表达式匹配块(请参阅a demo on regex101.com):

    {%\ for.*?%}
    (?s:.+?)
    {%\ endfor.*?%}
    

    每个块中查找成对的{{...}}

    {{\s*(.+?)\s*}}
    

    PHP中,可能是:

    <?php
    $data = <<<DATA
    {% for user in users %}
       Hello, {{ user.name }}, you are {{ user.age }} {{ user.name }}
    ssssssssssssssssssssss {{ user.name }}
    sdsddddddddddddddddddddddddddddd
    {% endfor %}
    
    {% for dog in dogs %}
       Your dog is {{ dog.age }} and likes {{ dog.food }}.
    {% endfor %}
    wwww
    {{ user.name }}
    DATA;
    
    $block = '~
                {%\ for.*?%}
                (?s:.+?)
                {%\ endfor.*?%}
                ~x';
    
    $variable = '~{{\s*(.+?)\s*}}~';
    
    if (preg_match_all($block, $data, $matches)) {
        foreach ($matches as $match) {
            if (preg_match_all($variable, $match[0], $variables, PREG_SET_ORDER)) {
                print_r($variables);
            }
    
        }
    }
    ?>
    

    <小时/> 广告2)

    将所有相关变量与整体表达式匹配。在这里,您需要\G(在最后一场比赛的位置匹配)和一些前瞻(参见a demo for this one at regex101.com as well):

    (?:{%\ for.+?%}
    |
    \G(?!\A)
    )
    (?s:(?!{%).)*?\K
    {{\s*(?P<variable>.+?)\s*}}
    

    现在让我们揭开这个表达的神秘面纱:

    (?:{%\ for.+?%}
    |
    \G(?!\A)
    )
    

    在这里,我们想要匹配{%\ for.+?%}(我们需要\,因为我们处于详细模式)位于最后一次匹配{{1 }}。现在,事实是,\G要么匹配最后一个匹配的位置,要么匹配字符串的最开头。我们不想要后者,因此是否定的。向前看\G

    下一部分

    (?!\A)

    快速前进&#34;对有趣的部分。

    分解,这说

    (?s:(?!{%).)*?\K
    

    现在,其余的很容易:

    (?s:        # open a non-capturing group, enabling the DOTALL mode
        (?!{%). # neg. lookahead, do not overrun {% (the closing tag)
    )*?         # lazy quantifier for the non-capturing group
    \K          # make the engine "forget" everything to the left
    

    它基本上与广告1的结构相同。

    同样,在{{\s*(?P<variable>.+?)\s*}} 中,这可能是:

    PHP

    <小时/> 尽管如此,实际上学习更复杂的模式通常是一个好主意,但另一方面却不能重新发明轮子 - 总有一个人比你更聪明。我可能考虑过几个边缘案例等等。