【问题标题】:Parse string into command and args in JavaScript将字符串解析为 JavaScript 中的命令和参数
【发布时间】:2023-04-06 03:07:01
【问题描述】:

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

【问题讨论】:

    标签: javascript regex string parsing


    【解决方案1】:

    可以使用正则表达式自行开发,但我强烈建议您查看以下任一方法:

    • minimist 子栈,或
    • yargs是对node参数解析的更全面的实现

    两者都久经沙场且得到很好的支持; minimist 每月的下载量约为 3000 万次,而 yargs 的下载量接近一半。

    您很可能可以找到一种方法来使用其中一种来获得所需的 CLI 语法,但 env 支持除外,IMO 应该单独处理(我无法想象您为什么想要对将环境变量设置为命令的一部分持意见)

    【讨论】:

    • yargs 不会处理配置文件格式 (FOO=bar cmd baz),对吗?
    • FOO=bar 在节点中根本不会出现在 process.argv 中,因此 yargs 和 minimist 都会忽略它。我强烈建议使用process.env 而不是尝试从命令中解析环境变量,因为可以通过多种方式设置它们,除非有非常具体的原因,否则限制对在命令开头设置的变量的支持将是出乎意料。
    • 所以,更清楚地说,我正在处理p-s,它允许您指定命令字符串,我将其作为子进程调用。对于cross-spawn,您需要分别提供commandargs。但是,如果我使用spawn-command,那么我不必这样做(我可以发送整个命令),这首先消除了我这样做的需要!
    【解决方案2】:

    虽然您可以使用原始正则表达式,但您正在构建的东西称为分词器。您需要分词器的原因是处理某些上下文,例如包含空格的字符串,您不想对其进行拆分。

    现有的通用库专门用于解析和标记化,可以处理字符串、块等情况。

    https://www.npmjs.com/package/js-parse

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

    【讨论】:

      【解决方案3】:

      正则表达式可以匹配你的命令行...

      ^\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;
      }
      

      【讨论】:

      • ?哇,谢谢!老实说,我认为现在我不需要这个,但我对你的正则表达式技能感到惊讶!
      猜你喜欢
      • 1970-01-01
      • 2019-09-04
      • 2016-07-30
      • 2016-12-10
      • 2023-03-21
      • 2020-11-11
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      相关资源
      最近更新 更多