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

时间:2015-11-22 11:26:49

标签: php regex preg-replace preg-match

我对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",我也希望匹配这些情况

2 个答案:

答案 0 :(得分:2)

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

以下是the regex

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

以下是人类话语中匹配的内容:

  • (?:\[foobar\b|(?!^)\G) - 一个领先的边界,正则表达式引擎应该在继续之前找到它,它匹配文字[foobar或上一次成功匹配的结束(\G匹配字符串start或者在最后一次成功比赛后立即定位,因为我们只需要后者,否则前瞻性(?!^)将排除字符串的开头。
  • \s+ - 一个或多个空格(必须使用属性值分隔标记名称)
  • \K - 正则表达式运算符,强制正则表达式引擎省略到目前为止抓取的所有匹配字符。 PCRE中积极观察背后的一个很酷的替代方案。
  • (?<key>[^=]+) - 命名捕获组“key”,匹配=以外的一个或多个字符。
  • =" - 匹配文字="序列 - (?<val>[^"]*) - 命名的捕获组“val”匹配0个或多个字符(由于*量词)而不是"
  • " - 一个文字",它是值子字符串的结束分隔符。
  • (?=\s+[^=]+="|]) - 一个积极的前瞻,确保有下一个属性或[tag xx="yy"...]实体的结尾。

PHP code

$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

答案 1 :(得分:0)

您可以使用以下功能:

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