我需要解析用于cross-spawn
的字符串来自以下字符串:
cmd foo bar
cmd "foo bar" --baz boom
cmd "baz \"boo\" bam"
cmd "foo 'bar bud' jim" jam
FOO=bar cmd baz
对象:
{command: 'cmd', args: ['foo', 'bar']}
{command: 'cmd', args: ['foo bar', '--baz', 'boom']}
{command: 'cmd', args: ['baz "boo" bam']}
{command: 'cmd', args: ['foo \'bar bud\' jim', 'jam']}
{command: 'cmd', args: ['baz'], env: {FOO: 'bar'}}
我认为正则表达式是可能的,但我希望避免写一些自定义的东西。有人知道有什么可以做到的吗?
问题和答案仍然很有价值,但对于我的具体用例,我不再需要这样做。我将使用spawn-command
代替(更准确地说,我会使用spawn-command-with-kill
),这不需要command
和args
分开。这将使我的生活更轻松。谢谢!
答案 0 :(得分:2)
可以推出自己的正则表达式,但我强烈建议你看看:
两者都经过战斗,并得到很好的支持;最小化者每月下载量约为3000万,而yargs接近一半。
你很有可能找到一种方法来使用其中一种来获得你想要的CLI语法,除了env
支持哪个IMO应该单独处理(我无法想象为什么你' d想要了解环境变量被设置为命令的一部分)
答案 1 :(得分:1)
正则表达式匹配您的命令行...
^\s*(?:((?:(?:"(?:\\.|[^"])*")|(?:'[^']*')|(?:\\.)|\S)+)\s*)$
...但你无法提取单个单词。相反,您需要匹配下一个字并将其累积到命令行中。
function parse_cmdline(cmdline) {
var re_next_arg = /^\s*((?:(?:"(?:\\.|[^"])*")|(?:'[^']*')|\\.|\S)+)\s*(.*)$/;
var next_arg = ['', '', cmdline];
var args = [];
while (next_arg = re_next_arg.exec(next_arg[2])) {
var quoted_arg = next_arg[1];
var unquoted_arg = "";
while (quoted_arg.length > 0) {
if (/^"/.test(quoted_arg)) {
var quoted_part = /^"((?:\\.|[^"])*)"(.*)$/.exec(quoted_arg);
unquoted_arg += quoted_part[1].replace(/\\(.)/g, "$1");
quoted_arg = quoted_part[2];
} else if (/^'/.test(quoted_arg)) {
var quoted_part = /^'([^']*)'(.*)$/.exec(quoted_arg);
unquoted_arg += quoted_part[1];
quoted_arg = quoted_part[2];
} else if (/^\\/.test(quoted_arg)) {
unquoted_arg += quoted_arg[1];
quoted_arg = quoted_arg.substring(2);
} else {
unquoted_arg += quoted_arg[0];
quoted_arg = quoted_arg.substring(1);
}
}
args[args.length] = unquoted_arg;
}
return args;
}
答案 2 :(得分:0)
虽然可以使用原始正则表达式,但您正在构建的内容称为tokenizer。你想要一个tokenizer的原因是处理某些上下文,比如包含空格的字符串,你不想拆分它们。
现有的通用库专为解析和标记化而设计,可以处理字符串,块等情况。
https://www.npmjs.com/package/js-parse
此外,大多数这些命令行格式和配置文件格式已经具有解析器/标记器。您可能希望利用这些,然后将每个结果标准化为对象结构。