将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 (\\\\"). 

其他一些说明:

  1. preg_split使用正则expression式来匹配string应被分割的标记。 在这种情况下,这不是你想要的。 你想返回正则expression式匹配的string部分。 为此,您应该使用preg_match (或者,如果像这样,您希望模式匹配多次) preg_match_all
  2. 还要考虑preg_match_allPREG_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。您必须删除(或重命名)该容器才能重新使用该名称。)