从正则表达式获得比括号更多的反向引用

时间:2010-02-11 15:09:59

标签: php regex preg-match

好的,这很难用英语解释,所以我只举一个例子。

我将使用以下格式的字符串:

key-value;key1-value;key2-...

我需要将数据提取为数组

array('key'=>'value','key1'=>'value1', ... )

我打算使用regexp来实现(大部分)此功能,并编写了这个正则表达式:

/^(\w+)-([^-;]+)(?:;(\w+)-([^-;]+))*;?$/

使用preg_match和此代码:

for ($l = count($matches),$i = 1;$i<$l;$i+=2) {
    $parameters[$matches[$i]] = $matches[$i+1];
}

然而,regexp显然只返回4个反向引用 - 输入字符串的第一个和最后一个键值对。有没有解决的办法?我知道我可以使用正则表达式来测试字符串的正确性并在循环中使用PHP的explode并获得完美的结果,但我真的好奇是否可以使用正则表达式。

简而言之,我需要通过正则表达式在字符串中捕获任意数量的这些key-value;对。

6 个答案:

答案 0 :(得分:2)

正则表达式是强大的工具,但有时候,它不是最好的方法。

$string = "key-value;key1-value";
$s = explode(";",$string);
foreach($s as $k){
    $e = explode("-",$k);
    $array[$e[0]]=$e[1];
}
print_r($array);

答案 1 :(得分:2)

请改用preg_match_all()。也许是这样的:

$matches = $parameters = array();
$input = 'key-value;key1-value1;key2-value2;key123-value123;';

preg_match_all("/(\w+)-([^-;]+)/", $input, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
   $parameters[$match[1]] = $match[2];
}

print_r($parameters);

编辑:

首先验证输入字符串是否符合模式,然后使用:

if (preg_match("/^((\w+)-([^-;]+);)+$/", $input) > 0) {
    /* do the preg_match_all stuff */
}       

EDIT2:最后一个分号是可选的

if (preg_match("/^(\w+-[^-;]+;)*\w+-[^-;]+$/", $input) > 0) {
    /* do the preg_match_all stuff */
}       

答案 2 :(得分:2)

您可以在提取匹配项时使用前瞻来验证输入:

/\G(?=(?:\w++-[^;-]++;?)++$)(\w++)-([^;-]++);?/

(?=(?:\w++-[^;-]++;?)++$)是验证部分。如果输入无效,匹配将立即失败,但每次应用正则表达式时仍会评估前瞻。为了使它(以及正则表达式的其余部分)与键值对保持同步,我使用\G将每个匹配锚定到上一个匹配结束的位置。

这样,如果前瞻第一次成功,则保证每次都成功。显然它没有那么高效,但这可能不会成为问题 - 只有你的测试才能确定。

如果前瞻失败,preg_match_all()将返回零(false)。如果成功,匹配将以数组数组的形式返回:一个用于完整的键值对,一个用于键,一个用于值。

答案 3 :(得分:0)

没有。较新的比赛会覆盖较旧的比赛。爆炸时,limit的{​​{1}}参数可能会有所帮助。

答案 4 :(得分:0)

这个解决方案怎么样:

$samples = array(
    "good" => "key-value;key1-value;key2-value;key5-value;key-value;",
    "bad1" => "key-value-value;key1-value;key2-value;key5-value;key-value;",
    "bad2" => "key;key1-value;key2-value;key5-value;key-value;",
    "bad3" => "k%ey;key1-value;key2-value;key5-value;key-value;"
);

foreach($samples as $name => $value) {
    if (preg_match("/^(\w+-\w+;)+$/", $value)) {
        printf("'%s' matches\n", $name);
    } else {
        printf("'%s' not matches\n", $name);
    }
}

答案 5 :(得分:0)

我认为您无法使用一个正则表达式验证和提取数据,因为您需要锚点(^$)进行验证,preg_match_all()表示数据,但是如果你使用preg_match_all()的锚点,它将只返回最后一组匹配的。