问题:将字符串解析为从命令行输出的数组

我正在开发一个新的 Symfony 2 项目,该项目将成为 Docker 容器的面板管理。

在这个项目中,我正在使用exec()PHP 函数执行一些命令。

我正在尝试解析以下命令的输出:

docker create tutum/lamp:latest --name test 2>&1

当命令成功时,我会在一个很好且易于使用的字符串中获取容器 ID,但是当出现问题时,它就不一样了。结果是一个带有 varu003d"data" 语法的字符串,我想解析它以获得一个数组。

命令输出:

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" ...);

我知道我必须进行正则表达式解析。过了一会儿(正则表达式和我不是真正的好朋友)我得到了这个正则表达式(在https://regex101.com/上测试):

/([a-zA-Z]+)="((.*)*)"/

我使用了 preg_split 函数,我不确定它是否好用。

preg_split('/([a-zA-Z]+)="((.*)*)"/', $output)

结果是:

array(2) { [0]=> string(0) "" [1]=> string(0) "" }

你有什么建议可以帮助我吗?非常感谢您的帮助。

解答

TL;DR: 这应该有效:

preg_match_all(',([a-z]+)="((?:[^"]|\\\\")*[^\\\\])",', $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."
  }
}

为什么这样有效

正则表达式解释:

([a-z]+)                    # 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使用正则表达式来匹配应该分割字符串的token。在这种情况下,这不是您想要的;你想返回被正则表达式_匹配_的字符串部分。为此,您应该使用preg_match(或者,如果像这里一样,您希望一个模式匹配多次),preg_match_all

  1. 还要考虑preg_match_allPREG_SET_ORDER标志。此标志使$matches结果包含来自输出消息的每个标签的一行,这使得数据结构易于处理。试着看看如果你把它排除在外会发生什么。
Logo

云原生社区为您提供最前沿的新闻资讯和知识内容

更多推荐