【问题标题】:Extract chars enclosed in complex brackets within a string in most efficient way以最有效的方式提取字符串中复杂括号中的字符
【发布时间】:2017-07-27 08:47:48
【问题描述】:

我有一个字符串,其中有括号,括号中可能是另一个括号。例如:

var string1 = "1 a (C(b(c+ d)e-fg)) 3# 4df (h j) 5 6 ((k))";

每个开括号都是闭合的,但不一定是立即闭合的,这意味着一个括号内可能是另一个括号。字符、数字和其他符号,如 + - # $ %(不包括 '!")可以遍布整个字符串、分组或单独。

我想要的是从括号中提取每个字符(无论它是数字、字母、符号...),并格式化这些字符,并用一个空格分隔,包括如果有字符立即一个接一个地出现,例如“c+”或“e-fg”,它们将被组合在一起。在上面的例子中,结果是:

var string2 = "C b c+ d e-fg h j k";

我有这样的代码:

var string1 = '1 a (C(b(c+ d)e-fg)) 3# 4df (h j) 5 6 ((k))';
var opens = new Array();
opens.push(string1.indexOf('('));
string1 = string1.replace('(','!')
var closes = new Array();
var done = false;
while (!done) {
    openindex = string1.indexOf('(');
    closeindex = string1.indexOf(')');
    string1 = string1.replace(')','!').replace('(','!');
    if (openindex>closeindex) {
        opens.push(openindex);
        closes.push(closeindex);
    }
    if (string1.indexOf(')')==-1) {
        closes.push(closeindex);
        done = true;
    }
}
var string2 = '';
for (var i=0;i<opens.length;i++) string2 = string2 + string1.substring(opens[i],closes[i]);
string2 = string2.replace(/!!/g,'  ').replace(/!/g,' ').replace(/  /g,' ');

这可行 (https://jsfiddle.net/nL2gp80j/1/),但我正在寻找更有效的解决方案。我不知道正则表达式,也许用它可以更好更快地完成。

【问题讨论】:

    标签: javascript regex string performance


    【解决方案1】:

    使用这个正则表达式/[^a-z]*/ig它将替换除char之外的所有内容

    var string1 = "1 2 (a(b(c d)efg)) 3 4 (h j) 5 6 ((k))";
    string1 = string1.match(/[a-z]+/ig);
    string1=string1.join(" ");
    console.log(string1);

    [编辑自评论@Jai]

    【讨论】:

    • 不,字符串是混合的,字符不仅在括号内。正如我在问题中所写,我只使用数字以获得更好的视觉效果。在实际场景中,字符和其他符号(如 + - $ % 等)遍布整个字符串。
    • 这将消除所有括号和空格,它返回:abcdefghjk。但他也想要这些空间。
    • @HenryP 而不是用.match() 方法否定更好的接受和提取。
    【解决方案2】:

    使用正则表达式通过分组提取字母。使用带有正则表达式的String.prototype.match() 方法作为参数:

    var str = "1 2 (a(b(c d)efg)) 3 4 (h j) 5 6 ((k))";
    var ex = str.match(/([a-z])+/g); // will give you grouped letters
    console.log(ex.join(" ")); // and join it with a space.

    【讨论】:

      【解决方案3】:

      如果确保括号调整正确,请使用此选项。

      var string1 = "1 2 (a(b(c d)efg)) 3 4 (h j) 5 6 ((k))";
      string1 = string1.replace(/[\(\)]*/ig,'');
      alert(string1);
      

      注意:我编辑了替换字符串,因为出现了复制粘贴错误。

      【讨论】:

      • 我不知道这是否接近。问题是字符不仅在括号内,所有类型的字符都在实际情况下的字符串中,正如我在问题中解释的那样。我只分隔数字和字符以便于可视化。
      【解决方案4】:

      我没有看到仅在一个正则表达式中执行此操作的简单方法,但这可以完成工作:

          var string1 = "1 a (C(b(c+ d)e-fg)) 3# 4df (h j) 5 6 ((k))";
          // remove before the first (
          string1 = string1.replace(/^[^()]*\(/, '(');
          // reome after the last )
          string1 = string1.replace(/\)[^()]*$/g, ')');
          // remove outside parenthesis
          string1 = string1.replace(/\)[^()]+\(/g, ')(');
          // while there is at least one (
          while (string1.indexOf('(') != -1) {
              // remove pair of parenthesis
              string1 = string1.replace(/\(([^()]+)\)/g, " $1 ");
          }
          // remove superfluous spaces
          string1 = string1.replace(/ +/g, ' ');
          console.log(string1);

      【讨论】:

      • 很好,就是这样,一个正则表达式解决方案。这比原始代码快吗?
      • 如果字符串是1 a (C(b(c+ d)e-fg(test))) 3# 4df (h j) 5 6 ((k)),那就不对了
      【解决方案5】:

      有一种更短更好的方法可以在不涉及更多正则表达式的情况下获得所需的结果:

      str = '1 a (C(b(c+ d)e-fg)) 3# 4df (h j) 5 6 ((k))';
      array = [], counter = 0;
      
      str.split(/([()])/).filter(Boolean).forEach(function(e, i, a) {
          // Increase / decrease counter and push desired values to an array
          e == '(' ? counter++ : e == ')' ? counter-- : counter > 0 ? array.push(e) : true;
          if (i === a.length - 1)
          	// Join all values with a whitespace between
      	console.log(array.join(' '));
      });

      【讨论】:

      • 感谢您仔细检查以前接受的解决方案!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多