正则表达式:解析多个引用的名称/值对

问题描述 投票:0回答:1

使用PHP 5.6 / 7.0。

我已经尝试了几个问题的几个正则表达式和几个正则表达式网站上的几个小时,并找不到任何能让我得到我需要的东西。我有一个像这样的字符串:

At vero eos et accusamus et iusto odio dignissimos ducimus

<!-- @@include default="/admin/creditapp/templates/longform/" try="/wTemplates/forms/templates/" file="credit_row_1.txt" -->

qui blanditiis praesentium voluptatum deleniti atque corrupti

<!-- @@include default="/admin/creditapp/templates/longform/" try="/wTemplates/forms/templates/" file="credit_row_2.txt" -->

quos dolores et quas excepturi sint

我在寻找以下来自令牌的比赛:

<!-- @@include ...the whole thing... -->
default
/admin/creditapp/templates/longform
try
/wtemplates/forms/templates
file
credit_row_1.txt

每当整个群体被发现时,自然会重复。我可以循环文件并完成它,所以一次只有一个实例是好的。我能提出的唯一表达方式就是:

<!-- @@include (?:(try|default|file)=\"(.+?)\"?)(?:\s*)(?:(try|default|file)=\"(.+?)\"?)(?:\s*)(?:(try|default|file)=\"(.+?)\"?)(?:\s*)-->

这是巨大的,并且不允许其他可能性,例如,我不知道,“(尝试| foo | bar |默认)”或某事,或者省略“尝试”或“默认”,例如“(FOO |栏|文件)。”

在模板中

<!-- @@include    -->

是不变的。里面可以是2到n名称=值对。我试过了:

(<!-- @@include (?:(try|default|file)=\"(.+?)\" ?){1,3}-->)

但它只返回找到的姓氏=值。我想我很接近,但我无法解决这个问题。

php regex pcre
1个回答
1
投票

PCRE无法存储重复捕获组的不同内容。重复该组时,先前的内容将被当前内容覆盖,依此类推。 一个解决方法是使用preg_match_all并使用与前一个匹配后匹配下一个位置的\G锚点(默认情况下它也匹配字符串的开头)。

preg_match_all('~(?:\G(?!\A)|<!-- @@include)\s+(try|default|file)="(.*?)"~', $str, $matches);

这种模式的想法是用第二个分支<!-- @@include成功进行第一场比赛,然后用第一个分支\G(?!\A)进行所有其他连续比赛。当部分\s+(try|default|file)="(.*?)"失败时,连续性被破坏,正则表达式引擎必须找到下一次出现的<!-- @@include才能继续。

如果您想知道第二个分支何时成功,您只需要在第二个分支中放置一个捕获组:

$result = [];

if ( preg_match_all('~(?:\G(?!\A)|<!-- (@)@include)\s+(try|default|file)="(.*?)"~', $str, $matches, PREG_SET_ORDER) ) {
    foreach ($matches as $m) {
        if ( !empty($m[1]) ) { // test which branch succeeds
            if ( isset($temp) )
                $result[] = $temp;
            $temp=[];
        }
        $temp[$m[2]] = $m[3];    
     }
}

if ( isset($temp) )
    $result[] = $temp;

demo


对于更灵活且能够处理未知密钥的东西,您可以使用两个preg_match_all

$result = [];

if ( preg_match_all('~<!-- @@include\s+\K\w+=".*?"(?:\s+\w+=".*?")*~', $str, $matches) ) {
    foreach ($matches[0] as $params) {
        if ( preg_match_all('~(\w+)="(.*?)"~', $params, $keyvals) )
            $result[] = array_combine($keyvals[1], $keyvals[2]);
    }
}

print_r($result);

demo

请注意,对于大字符串,最后一个解决方案可能更有效,因为第一个模式不是以交替开始,而是以文字字符串开头(在这种情况下,pcre正则表达式引擎能够优化研究)。第二种模式只需要处理短字符串,所以这不是问题。

© www.soinside.com 2019 - 2024. All rights reserved.