在JavaScript中将字符串解析为命令和args

时间:2016-09-03 06:05:19

标签: javascript regex string parsing

我需要解析用于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),这不需要commandargs分开。这将使我的生活更轻松。谢谢!

3 个答案:

答案 0 :(得分:2)

可以推出自己的正则表达式,但我强烈建议你看看:

  • minimist来自Substack,或
  • yargs这是对节点
  • 的参数解析的更全面的实现

两者都经过战斗,并得到很好的支持;最小化者每月下载量约为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

此外,大多数这些命令行格式和配置文件格式已经具有解析器/标记器。您可能希望利用这些,然后将每个结果标准化为对象结构。