问题描述
比方说,我在mikrotik路由器中有以下脚本,我想提取一个包含键和值的数组,如果还有另一个包含 = 字符的值,该怎么做
add name=100YER on-login=":do {:put \"a\";} on-error={};" rate-limit=256k/512k
结果应如下所示:
$result=array ('name'=>'100YER',on-login=>':do {:put \"a\";} on-error={};','rate-limit'=>'256k/512k');
我使用此正则表达式将其除以 = ,但问题出在登录值上。
if (preg_match_all('/[^=]+/i',$response,$MATCHES) ){
//
}
解决方法
您可以将2个捕获组与分支重置组一起使用:
(\w+(?:-\w+)*)=(?|"((?:[^"]+|(?<=\\)")++)"|([^"\s]+))
说明
-
(
捕获第1组-
\w+(?:-\w+)*
匹配1个以上字符的字符,然后可选地跟一个-
和1个以上字符的字符
-
-
)
关闭第1组 -
=
字面上匹配 -
(?|
分支重置组-
"(
匹配"
并开始第2组-
(?:[^"]+|(?<=\\)")++
匹配除"
或\"
之外的所有字符
-
-
)"
关闭第2组并匹配"
-
|
或 -
([^"\s]+)
捕获第3组,匹配"
或空白char 以外的任何字符
-
-
)
关闭分支重置组
例如
$re = '/(\w+(?:-\w+)*)=(?|"((?:[^"]+|(?<=\\\\)")++)"|([^"\s]+))/';
$str = 'add name=100YER on-login=":do {:put \\"a\\";} on-error={};" rate-limit=256k/512k';
preg_match_all($re,$str,$matches);
$result = array_combine($matches[1],$matches[2]);
print_r($result);
输出
Array
(
[name] => 100YER
[on-login] => :do {:put \"a\";} on-error={};
[rate-limit] => 256k/512k
)
,
要改善@Thefourthbird的模式,请使用PHP: Regex to ignore escaped quotes within quotes中“最佳”技术的智慧。这样不仅可以提高步数的图形效率,还可以更准确地区分字面使用的反斜杠和转义的反斜杠。
否则,我完全同意分支重置最适合将目标子字符串保留在preg_match_all()
输出数组的一致列中。
代码:(Demo)
$string = <<<MIKROTIK
add name=100YER on-login=":do {:put \"a\";} on-error={};" rate-limit=256k/512k
MIKROTIK;
var_export(
preg_match_all(
'~(\w+(?:-\w+)*)=(?|"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|([^" ]+))~',$string,$out
)
? array_combine($out[1],$out[2])
: []
);
输出:
array (
'name' => '100YER','on-login' => ':do {:put \\"a\\";} on-error={};','rate-limit' => '256k/512k',)