将stringparsing为从命令行输出的数组
我正在开发一个新的Symfony 2项目,这个项目将是Docker容器的面板pipe理。
在这个项目中,我使用exec()
PHP函数执行一些命令。
我试图parsing下面的命令的输出:
docker create tutum/lamp:latest --name test 2>&1
当命令是成功的,我得到了一个string的容器ID是好的,易于使用,但出现问题时,它是不一样的。 结果是一个带有var =“data”语法的string,我想要parsing它以获得数组。
命令输出:
time="2015-06-21T11:33:26+02:00" level="fatal" msg="Error response from daemon: Conflict. The name \"test\" is already in use by container XXXXXXXX. You have to delete (or rename) that container to be able to reuse that name."
我希望有这样的事情:
Array( time => "2015-06-21T11:33:26+02:00", level => "fatal" ...);
我知道我必须做一个正则expression式parsing。 过了一段时间(正则expression式和我不是真正的最好的朋友)我得到这个正则expression式(在https://regex101.com/testing):
/([a-zA-Z]+)="((.*)*)"/
我用preg_split函数,我不知道这是好的。
preg_split('/([a-zA-Z]+)="((.*)*)"/', $output)
结果是:
array(2) { [0]=> string(0) "" [1]=> string(0) "" }
你有什么build议来帮助我吗? 非常感谢您的帮助。
TL; DR:这应该工作:
preg_match_all(',([az]+)="((?:[^"]|\\\\")*[^\\\\])",', $a, $matches, PREG_SET_ORDER); var_dump($matches);
最后一个var_dump
打印下面的数据结构,应该很容易处理:
array(3) { [0] => array(3) { [0] => string(32) "time="2015-06-21T11:33:26+02:00"" [1] => string(4) "time" [2] => string(25) "2015-06-21T11:33:26+02:00" } [1] => array(3) { [0] => string(13) "level="fatal"" [1] => string(5) "level" [2] => string(5) "fatal" } [2] => array(3) { [0] => string(179) "msg="Error response from daemon: Conflict. The name \\"test\\" is already in use by container XXXXXXXX. You have to delete (or rename) that container to be able to reuse that name."" [1] => string(3) "msg" [2] => string(173) "Error response from daemon: Conflict. The name \\"test\\" is already in use by container XXXXXXXX. You have to delete (or rename) that container to be able to reuse that name." } }
为什么这个工作
正则expression式解释说:
([az]+) # Match the label ("time", "level" or "msg") = # Self-explanatory "((?:[^"]|\\\\")*[^\\\\])" # This is the tricky part: # Match the quoted string; this is a sequence # of (a) non-quote characters ([^"]) or # (b) escaped quote characters (\\\\").
其他一些说明:
-
preg_split
使用正则expression式来匹配string应被分割的标记。 在这种情况下,这不是你想要的。 你想返回正则expression式匹配的string部分。 为此,您应该使用preg_match
(或者,如果像这样,您希望模式匹配多次)preg_match_all
。 - 还要考虑
preg_match_all
的PREG_SET_ORDER
标志。 该标志使得$matches
结果包含输出消息中每个标签的一行,这使得数据结构易于处理。 试着看看如果你把它抛出去会发生什么。
这是因为贪婪的点把你的string吃掉了。“让它变懒,会这样做:
if(preg_match_all('/(\w+)="(.*?)(?<!\\\)"/s', $str, $out)) print_r(array_combine($out[1], $out[2]));
\w
是[a-zA-Z0-9_]
。 向后看(?<!\\\)
吃掉了引号( 参见regex101 )。
用于制作点匹配换行符s
标志。 在eval.intesting , 输出到:
Array([time] => 2015-06-21T11:33:26 + 02:00 [level] => fatal [msg] =>来自守护进程的错误响应:Conflict。名称\“test \容器XXXXXXXX。您必须删除(或重命名)该容器才能重新使用该名称。)