是否有原生的“PHP 方式”来解析来自 string
的命令参数?例如,给定以下 string
:
foo "bar \"baz\"" '\'quux\''
我想创建以下数组
:
array(3) {
[0] =>
string(3) "foo"
[1] =>
string(7) "bar "baz""
[2] =>
string(6) "'quux'"
}
我已经尝试利用 token_get_all()
, 但 PHP 的变量插值语法(例如 "foo ${bar} baz"
)几乎让我大吃一惊。
我很清楚我可以编写自己的解析器。命令参数语法非常简单,但如果有现有的本地方法来执行此操作,我更愿意使用它而不是自己动手。
编辑:请注意,我希望从 string
中解析参数,而不是从 shell/命令行中解析。
编辑 #2:下面是一个更全面的参数预期输入 -> 输出示例:
foo -> foo
"foo" -> foo
'foo' -> foo
"foo'foo" -> foo'foo
'foo"foo' -> foo"foo
"foo\"foo" -> foo"foo
'foo\'foo' -> foo'foo
"foo\foo" -> foo\foo
"foo\\foo" -> foo\foo
"foo foo" -> foo foo
'foo foo' -> foo foo
最佳答案
正则表达式非常强大:(?s)(?<!\\)("|')(?:[^\\]|\\.)*?\1|\S+
.那么这个表达式是什么意思?
-
(?s)
: 设置s
用点匹配换行符.
-
(?<!\\)
: negative lookbehind,检查下一个标记前是否没有反斜杠 -
("|')
: 匹配单引号或双引号并将其放入第 1 组 -
(?:[^\\]|\\.)*?
: 匹配除\以外的所有内容,或将\与紧随其后的(转义)字符匹配 -
\1
: 匹配第一组匹配的内容 -
|
: 或 -
\S+
: 匹配除空格以外的任何内容一次或多次。
我们的想法是捕捉一个引语并将其分组以记住它是单引号还是双引号。负面回顾是为了确保我们不匹配转义引号。 \1
用于匹配第二对引号。最后我们使用交替来匹配任何不是空格的东西。这个解决方案很方便,几乎适用于任何支持回顾和反向引用的语言/风格。当然,此解决方案期望报价已关闭。结果在第 0 组中找到。
让我们用 PHP 来实现它:
$string = <<<INPUT
foo "bar \"baz\"" '\'quux\''
'foo"bar' "baz'boz"
hello "regex
world\""
"escaped escape\\\\"
INPUT;
preg_match_all('#(?<!\\\\)("|\')(?:[^\\\\]|\\\\.)*?\1|\S+#s', $string, $matches);
print_r($matches[0]);
如果您想知道我为什么使用 4 个反斜杠。那就看看我的previous answer .
输出
Array
(
[0] => foo
[1] => "bar \"baz\""
[2] => '\'quux\''
[3] => 'foo"bar'
[4] => "baz'boz"
[5] => hello
[6] => "regex
world\""
[7] => "escaped escape\\"
)
<知识库> Online regex demo <知识库> Online php demo
删除引号
使用命名组和一个简单的循环非常简单:
preg_match_all('#(?<!\\\\)("|\')(?<escaped>(?:[^\\\\]|\\\\.)*?)\1|(?<unescaped>\S+)#s', $string, $matches, PREG_SET_ORDER);
$results = array();
foreach($matches as $array){
if(!empty($array['escaped'])){
$results[] = $array['escaped'];
}else{
$results[] = $array['unescaped'];
}
}
print_r($results);
关于php - 在 PHP 中解析命令参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17848618/