5

我想获取参数数组,这样我就可以将它与optparse-js 库一起使用,所以如果我有类似的东西

-f foo -b -a -z baz bar

我想要这样的数组

["-f", "foo", "-b", "-a", "-z", "baz", "bar"]

它应该适用于内部有转义引号和长 GNU 选项的字符串。到目前为止,我有匹配字符串的正则表达式

/("(?:\\"|[^"])*"|'(?:\\'|[^'])*')/g

"das"它匹配类似or"asd\"asd"'asd'or的字符串'sad\'asd'

我可以为此使用正则表达式还是我需要一个解析器(比如使用 PEG)如果它匹配正则表达式会很好,这样我就可以做到

-p "hello b\"ar baz" -f /^ [^ ]+ $/

更新:在@Damask 的帮助下,我创建了这个正则表达式:

/('(\\'|[^'])*'|"(\\"|[^"])*"|\/(\\\/|[^\/])*\/|(\\ |[^ ])+|[\w-]+)/g

它适用于这样的字符串:

echo -p "hello b\"ar baz" -f /^ [^ ]+ $/

它返回

['echo', '-p', '"hello b\"ar baz"', '-f', '/^ [^ ]+ $/']

但如果在这样的字符串上失败:

echo "©\\\\" abc "baz"

它匹配命令和两个参数而不是 3 个参数演示

如果参数没有像 "foo"baz 这样的空格,它应该是数组中的一项,需要包含引号,但我会从字符串中删除未转义的那些(就像在 bash 中执行echo "foo"barecho 时会得到一个 foobar 参数)。

4

8 回答 8

4

一些评论:

  • 引号的原始正则表达式是这个
    "[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'
    例子:http ://regex101.com/r/uxqApc/2

  • 这部分(?= :? | $ )将始终解析为 true,并且无用

  • 这部分/(\\/|[^/])+/[gimy]*如果这是一个正则表达式(或任何分隔项)
    ,您必须盲目处理转义任何内容。像这样/[^/\\]*(?:\\[\S\s][^/\\]*)*/[gimy]*
    否则它将匹配/..\\//不正确的。

  • 这个表达式(?: \\ \s | \S )+在交替序列中是第一个,即在这个之前[\w-]+。由于 not whitespace\S是 的超集[\w-],这意味着[\w-]+永远不会到达。

进行更正并将它们重新组合在一起得到这个正则表达式:
/("[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S)+)/

演示:

JavaScript - http://regex101.com/r/cuJuQ8/1
PCRE - http://regex101.com/r/cuJuQ8/2

格式化

 (                             # (1 start)
      "
      [^"\\]* 
      (?: \\ [\S\s] [^"\\]* )*
      "
   |  
      ' 
      [^'\\]* 
      (?: \\ [\S\s] [^'\\]* )*
      '
   |  
      / 
      [^/\\]* 
      (?: \\ [\S\s] [^/\\]* )*
      /
      [gimy]* 
      (?= \s | $ )
   |  
      (?: \\ \s | \S )+
 )                             # (1 end)


如果你也需要像空格(引号或正则表达式之外)也是分隔符一样解析它,那就是它:

/((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S))+)(?=\s|$)/

演示:

JavaScript - http://regex101.com/r/cuJuQ8/3
PCRE - https://regex101.com/r/cuJuQ8/4

格式化

 (                             # (1 start)
      (?:
           "
           [^"\\]* 
           (?: \\ [\S\s] [^"\\]* )*
           "
        |  
           ' 
           [^'\\]* 
           (?: \\ [\S\s] [^'\\]* )*
           '
        |  
           / 
           [^/\\]* 
           (?: \\ [\S\s] [^/\\]* )*
           /
           [gimy]* 
           (?= \s | $ )
        |  
           (?: \\ \s | \S )
      )+
 )                             # (1 end)
 (?= \s | $ )
于 2017-05-03T17:25:10.500 回答
4

我真的很喜欢正则表达式,但有时简单的正则表达式和简单函数的组合可以完成同样的工作,但更容易调试和维护,尤其是当不熟悉(复杂)正则表达式的开发人员加入项目时。

所以这是另一种方法,请参见下面的解释。

它使用这个相当复杂的样本进行测试,其中包含许多空格或根据需要转义双引号的参数:

echo "©\\\\" abc "baz" "foo bar dummy" -d "marty \\\"mc fly" -f "avb eer\"" -p 2 "asd\"asd" -a 3

代码片段

function commandArgs2Array(text) {
  const re = /^"[^"]*"$/; // Check if argument is surrounded with double-quotes
  const re2 = /^([^"]|[^"].*?[^"])$/; // Check if argument is NOT surrounded with double-quotes

  let arr = [];
  let argPart = null;

  text && text.split(" ").forEach(function(arg) {
    if ((re.test(arg) || re2.test(arg)) && !argPart) {
      arr.push(arg);
    } else {
      argPart = argPart ? argPart + " " + arg : arg;
      // If part is complete (ends with a double quote), we can add it to the array
      if (/"$/.test(argPart)) {
        arr.push(argPart);
        argPart = null;
      }
    }
  });

  return arr;
}

let result = commandArgs2Array('echo "©\\\\" abc "baz" "foo bar  dummy" -d "marty \\\"mc fly" -f "avb eer\"" -p 2 "asd\"asd" -a 3');
console.log(result);

解释

首先,使用空格字符分割参数。

对于每个参数,我们检查它是完整的还是不完整的参数

一个完整的论点是一个论点,它是

  • 用双引号括起来
  • 根本没有被双引号包围

其他所有情况都代表一个不完整的论点。要么

  • 不完整参数的开头(以双引号开头)
  • 空间
  • 不完整参数的一部分,可以包含转义的双引号
  • 不完整参数的结尾(以双引号结尾)

这就是所有的人!

于 2017-05-04T16:33:50.767 回答
2

你为什么不简单地使用拆分功能?

var arr = myString.split(/\s+/);

您最好将正则表达式作为参数传递,以避免在分隔符为\t或有多个空格等情况下出现错误。

编辑:

如果您的论点有空格并用引号引起来,我认为您找不到单个正则表达式。认为您应该首先找到带有空格的参数(/"(.*?)"/在第 1 组中您将获得参数),将它们添加到数组中,然后从字符串中删除它们,然后才使用上述拆分方法。

于 2012-12-10T07:23:08.823 回答
0

试试这个:

var a = '-f foo "ds  df s\\" da" -b -a -z baz bar';
a.match(/([\w-]+|"(\\"|[^"])*")/g)

返回[ "-f", "foo", ""ds df s\" da"", "-b", "-a", "-z", "baz", "bar"]

于 2012-12-10T07:47:54.413 回答
0

这将起作用:

var input = '-p "hello b\"ar baz" -f /^ [^ ]+ $/ -c -d -e'
var arr = input.split(' -');
var out = [];
for(var i = 0; i < arr.length; i++){
    if(~arr[i].indexOf(' ')){
        out = out.concat([arr[i].substring(0, arr[i].indexOf(' ')), arr[i].substring(arr[i].indexOf(' ')+1)])
    }else{
        out = out.concat('-'+arr[i]);
    }
}

输出:

["-p", ""hello b"ar baz"", "f", "/^ [^ ]+ $/", "-c", "-d", "-e"]

我知道这不是一个花哨的 1 行正则表达式,但它的工作方式与预期一样。

于 2012-12-10T07:51:11.157 回答
0
 var string = "-f foo -b -a -z baz bar";
        string = string.split(" ");
    var stringArray = new Array();
    for(var i =0; i < string.length; i++){
        stringArray.push(string[i]);
    }
    console.log(stringArray);

输出将是这样的控制台

数组 [“-f”、“foo”、“-b”、“-a”、“-z”、“baz”、“bar”]

于 2017-05-03T10:15:20.027 回答
-1

这个问题的另一个选择:https ://github.com/elgs/splitargs

于 2015-02-27T06:50:39.043 回答
-1

好的,即使我为这个问题创建了一个赏金,我在Regex match even number of letters的帮助下找到了答案

我的正则表达式看起来像这样:

/('((?:[^\\]*(?:\\\\)*\\')+|[^']*)*'|"(?:(?:[^\\]*(?:\\\\)*\\")+|[^"]*)*"|(?:\/(\\\/|[^\/])+\/[gimy]*)(?=:? |$)|(\\\s|\S)+|[\w-]+)/

带演示

编辑:@sin 建议制作更好的正则表达式:

/("[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|(?:\/(\\\/|[^\/])+\/[gimy]*)(?=:? |$)|(\\\s|\S)+|[\w-]+)/
于 2017-04-30T21:53:39.960 回答