是否可以将preg_match中的所有属性与空属性或缺少的属性进行匹配


Is it possible to match all attributes in a preg_match with empty or missing attributes?

我对pre_match有点问题。

我有一个字符串,可以按照任何顺序带有属性(例如[foobar a="b" c="d" f="g"][foobar c="d" a="b" f="g"][foobar f="g" a="b" c="d"]等)

这些是我尝试过的模式:

// Matches when all searched for attributes are present
// doesn't match if one of them is missing
// http://www.phpliveregex.com/p/dHi
$pattern = ''[foobar'b(?='s)(?=(?:(?!']).)*'s'ba=(["|'])((?:(?!'1).)*)'1)(?=(?:(?!']).)*'s'bc=(["'])((?:(?!'3).)*)'3)(?:(?!']).)*]'
// Matches only when attributes are in the right order
// http://www.phpliveregex.com/p/dHj
$pattern = ''[foobar's+a=["''](?<a>[^"'']*)["'']'s+c=["''](?<c>[^"'']*).*?']'

我正在想办法,但似乎做不好。

有没有办法匹配所有属性,即使其他属性丢失或为空(a='')?

我甚至在属性之间的空格处玩过explode,然后是str_replace,但这似乎太过分了,不是正确的方法。

在链接中,我只匹配了a="b"c="d",但我也想匹配这些情况,即使有e="f"z="x"

如果将[...]字符串作为单独的字符串,而不是在较大的文本中,则可以很容易地使用基于'G的正则表达式来标记起始边界([some_text),然后使用否定字符类将任何键值对与一些基本正则表达式子模式匹配。

这是正则表达式:

(?:'[foobar'b|(?!^)'G)'s+'K(?<key>[^=]+)="(?<val>[^"]*)"(?='s+[^=]+="|])

以下是它在人类语言中的匹配:

  • (?:'[foobar'b|(?!^)'G)-一个前导边界,正则表达式引擎应该在继续之前首先找到它,并且它与文字[foobar或上一次成功匹配的末尾相匹配('G与上次成功匹配后的字符串开始或位置相匹配,由于我们只需要后者,因此负前瞻(?!^)排除了字符串的开头)
  • 's+-1个或多个空白(它们是用属性值分隔标记名称所必需的)
  • 'K-正则表达式运算符,它强制正则表达式引擎省略迄今为止捕获的所有匹配字符。在PCRE中,这是一个很酷的替代方案
  • (?<key>[^=]+)-与=以外的1个或多个字符匹配的命名捕获组"密钥"
  • ="-匹配文字="序列-(?<val>[^"]*)-与"以外的0个或多个字符匹配的命名捕获组"val"(由于*量词)
  • "—文字",它是值子字符串的结束分隔符
  • (?='s+[^=]+="|])-确保存在下一个属性或[tag xx="yy"...]实体的末尾的积极前瞻

PHP代码:

$re = '/(?:'[foobar'b|(?!^)'G)'s+'K(?<key>[^=]+)="(?<val>[^"]*)"(?='s+[^=]+="|])/'; 
$str = "[foobar a='"b'" c='"d'" f='"g'"]"; 
preg_match_all($re, $str, $matches);
print_r(array_combine($matches["key"], $matches["val"]));

输出:[a] => b, [c] => d, [f] => g

您可以使用以下函数:

function toAssociativeArray($str) {
    // Single key/pair extraction pattern:
    $pattern = '('w+)'s*='s*"([^"]*)"';
    $res = array();
    // Valid string?
    if (preg_match("/'[foobar(('s+$pattern)*)']/", $str, $matches)) {
        // Yes, extract key/value pairs: 
        preg_match_all("/$pattern/", $matches[1], $matches);
        for ($i = 0; $i < count($matches[1]); $i += 1) {
            $res[$matches[1][$i]] = $matches[2][$i];
        }
    };
    return $res;
}

这就是你可以使用它的方式:

// Some test data:
$testData = array('[foobar a="b" c="d" f="g"]',
             '[foobar a="b" f="g" a="d"]',
             '[foobar f="g" a="b" c="d"]',
             '[foobar f="g" a="b"]',
             '[foobar f="g" c="d" f="x"]');
// Properties I am interested in, with a default value:
$base = array("a" => "null", "c" => "nothing", "f" => "");
// Loop through the test data:
foreach ($testData as $str) {
    // get the key/value pairs and merge with defaults:
    $res = array_merge($base, toAssociativeArray($str));
    // print value of the "a" property
    echo "value of a is {$res['a']} <br>";
}

此脚本输出:

value of a is b
value of a is d
value of a is b
value of a is b
value of a is null