将 mikrotik 脚本拆分为 key/value php 数组

Splitting mikrotik script into an key/value php array

比方说,我在 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,匹配除 " 以外的任何字符或空白字符
  • )关闭分支重置组

Regex demo | Php demo

例如

$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',
)