【问题标题】:regex to extract array indices正则表达式提取数组索引
【发布时间】:2016-08-27 23:20:13
【问题描述】:

我仍然很难理解正则表达式... :-/

给定字符串(类似 JavaScript 的表达式),比如这些......

  • foo[0]
  • foo[4][2]
  • foo[4][2][234523][3]

...我正在尝试解构正则表达式中的索引,以便我拥有

  • 变量名:foo
  • 单个索引:上一个示例中的 fox 示例 422345233

接受像

这样的无效语法
  • foo[23]bar[55]
  • foo[123]bar
  • [123]bla
  • foo[urrrr]

也可以忽略 foo [13]foo[ 123 ] 这样的空格,但这并不重要。

用正则表达式可以吗?

我能够使用var matches = s.match(/\[([0-9]?)\]/g); 提取括号,但结果中包含括号,缺少变量名称(可以绕过该问题),并且也不尊重上述边缘情况。

【问题讨论】:

  • 什么会被认为是有效的语法?例如,foo[23] bar[55] 是否有效,或者它们之间是否需要换行,或者右括号是否需要是最后一个字符?
  • foo[23]bar[55] 将是两个独立的示例。因此,单个字符串 foo[23] bar[55] 将是无效的。当X 是要解析的字符串时,var foo = X; 必须是有效的语法。我实际上是在尝试解码 JavaScript 语言的一个非常小的子集。
  • 你不能用正则表达式解析JS...

标签: javascript regex


【解决方案1】:

您必须使用循环来提取多个匹配项。这是一种方法:

function run(string) {
  var match;
  if(match = string.match(/^([^[]+)\s*(\[\s*(\d+)\s*\]\s*)+\s*$/)) {
    var variable = match[1], indices = [];
    var re = /\[\s*(\d+)\s*\]/g;
    while(match = re.exec(string)) {
      indices.push(+match[1]);
    }
    return { variable: variable, indices: indices };
  } else {
    return null;
  }
}

var strings = [
  "foo[0]",
  "foo[4][2]",
  "foo[4][2][234523][3]",
  "foo [13]",
  "foo[ 123 ]",
  "foo[1] [2]",
  "foo$;bar%[1]",
  // The following are invalid
  "foo[23]bar[55]",
  "foo[123]bar",
  "[123]bla",
  "foo[urrrr]",
];

// Demo
strings.forEach(function(string) {
  document.write("<pre>" + JSON.stringify(run(string), null, 4) + "</pre>");
});

【讨论】:

  • @UdoG 如果您尝试解析比这更复杂的表达式,您可能需要查看 PEG.js 或其他 JS 解析器生成器或组合库。
  • 谢谢,但我不需要更复杂的表达式。由于您还包括对空格的支持:是否可以允许像foo[1] [2](括号之间的空格)这样的字符串?
  • 另外,是否可以在第一个括号之前接受 anything,甚至是 `foo$;bar%´ - 是的,我在我的问题中并不清楚这一点,对不起
【解决方案2】:

那是not possible

你可以测试它是否是一个正确的陈述,只要你知道你有多少个索引你就可以选择它们,但是没有办法用javascript.exec多次捕获一个组。

但是语言是常规的。所以应该是这样的:

^([a-zA-Z][a-zA-Z_0-9]*)(\[[0-9]*\])*

第一组将匹配变量,第二组(*quantifier 0-n 次)索引。

因此,如果您想这样做,我建议使用另一种解析方法:

function parse(str) {
  let idx = 0;
  while(str[idx+1] != '[') {
    idx++;
  }

  let name = str.substr(0, idx+1);


  let indices = [];
  while(str[idx+1] == '[') {
    idx++;
    let startIdx = idx;
    while(str[idx+1] != ']') {
      idx ++;
    }
    console.log(idx);
    indices.push(str.substr(startIdx+1, idx-startIdx));
    idx++;
  }

  return {name,indices};
}

【讨论】:

    【解决方案3】:

    这是获得所需数组的 2 步正则表达式的小 ES6 版本:

    function interpret(s) {
        return (/^(\w+)\s*((?:\[\s*\d+\s*\]\s*)*)$/.exec(s) || [,null]).slice(1).reduce(
            (fun, args) => [fun].concat(args.match(/\d+/g))); 
    }
    
    var s = 'foo[4][2][234523][3]';
    var result = interpret(s);
    console.log(result);

    它首先通过exec() 获取两个主要部分,它返回完整匹配、函数名和数组中的其余部分(包含 3 个元素)。然后使用slice(1),它会忽略这三个中的第一个。另外两个传递给reduce

    reduce 回调只会被调用一次,因为没有提供初始值。

    这很方便,因为它实际上意味着回调将这两个部分作为它的两个参数。它应用第二个正则表达式来拆分索引字符串,并返回最终的数组。

    || [,null] 将处理原始匹配失败的情况:它确保reduce 作用于[null],因此将返回null

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多