【问题标题】:How to match balanced non empty brackets?如何匹配平衡的非空括号?
【发布时间】:2016-06-03 20:50:49
【问题描述】:

使用正则表达式,给定以下文本,如何匹配平衡方括号之间的内容,但前提是不为空?

{
    "key1": [
        {
            "key2": "",
            "key3": "",
            "key4": "",
            "key5": []
        }
    ],
    "key6": [
        {
            "key7": "",
            "key8": "",
            "key9": [
                {
                    "key10": "",
                    "key11": "",
                    "key12": "",
                    "key13": []
                }
            ],
            "key14": ""
        }
    ],
    "key15": [],
    "key16": []
}

/\[([\s\S]+)\]/g:这是我的尝试,我的想法是匹配第一个和最后一个括号,但这不起作用,因为我们不想匹配空括号,即[]。它也不平衡,因此它不正确地匹配key1 的左方括号和key16 的右方括号。

应该匹配key1 的左括号和右括号(即平衡)。因为我们不想匹配空的[],所以我们必须保持平衡,否则我们将匹配错误的开始和结束括号。

我要解决的实际问题是删除 [ ] 如果不为空。此正则表达式将在代码中递归运行,以便它不断删除括号,直到找不到更多匹配项。我确实想在 RegEx 中递归地应用它,但无法解决。

生成的文本应如下所示:

{
    "key1": {
        "key2": "",
        "key3": "",
        "key4": "",
        "key5": []
    },
    "key6": {
        "key7": "",
        "key8": "",
        "key9": {
            "key10": "",
            "key11": "",
            "key12": "",
            "key13": []
        },
        "key14": ""
    },
    "key15": [],
    "key16": []
}

您可以在这里查看和使用我的正则表达式: https://regex101.com/r/bE0jM5/5

提前致谢

【问题讨论】:

  • 有什么理由拒绝投票?

标签: regex string pcre


【解决方案1】:

这个小怪物

/\[((\[\s*\]|[^\[\]])+)\]/

似乎可以解决问题:

text = document.querySelector('pre').textContent;

while(1) {
  
  var r = text.replace(/\[((\[\]|[^\[\]])+)\]/g, "$1");
  if(r === text) break;
  text = r;
}

document.querySelector('pre').textContent = text;
<pre>
{
    "key1": [
        {
            "key2": "",
            "key3": "",
            "key4": "",
            "key5": []
        }
    ],
    "key6": [
        {
            "key7": "",
            "key8": "",
            "key9": [
                {
                    "key10": "",
                    "key11": "",
                    "key12": "",
                    "key13": []
                }
            ],
            "key14": ""
        }
    ],
    "key15": [],
    "key16": []
}
</pre>

如果您的输入实际上是 JSON,最好将其解析并作为对象操作,而不是不可读且易碎的正则表达式:

text = document.querySelector('pre').textContent;

removeArrays = function(obj) {
  
  if(Array.isArray(obj) && obj.length === 1)
    return removeArrays(obj[0]);
  
  if(typeof obj === "object")
    for(var k in obj)
      obj[k] = removeArrays(obj[k]);
  
  return obj;
}

s = removeArrays(JSON.parse(text));

document.querySelector('pre').textContent = JSON.stringify(s,0,3);
<pre>
{
    "key1": [
        {
            "key2": "",
            "key3": "",
            "key4": "",
            "key5": []
        }
    ],
    "key6": [
        {
            "key7": "",
            "key8": "",
            "key9": [
                {
                    "key10": "",
                    "key11": "",
                    "key12": "",
                    "key13": []
                }
            ],
            "key14": ""
        }
    ],
    "key15": [],
    "key16": []
}
</pre>

【讨论】:

  • 差不多了...我应该指出空数组可能有空格或换行符,应该保留但也不匹配,所以当我的意思是忽略空数组时,我的意思也是[ ] .目前,如果我在 key5 的数组中间添加一个空格或换行符,则该数组不正确匹配,因为它仍然是空的。
  • @Camsoft:重新编辑...但这就是为什么您应该尝试使用 json 代替或重新使用的原因。
  • 你说得对,它是 JSON,但它是由 iOS 框架生成的。它已经通过了一次,所以已经修改了,我只是想删除剩余的大括号以使其再次有效。所有正则表达式的实际原因是因为我需要保留对象的顺序,但在 iOS 中我必须使用对象数组来保留顺序,所以我不得不在后期处理中删除所有数组。除了人类之外的任何人实际上都不会读取 JSON 来调试对象图,因此 JSON 格式只是为了使其格式化。
  • 看起来它仍然匹配空数组:regex101.com/r/bE0jM5/6 - 我已经递归了一次,现在key5的空数组已经被删除了。
  • @Camsoft:您可以在主循环之前再通过一次,将\[\s+\] 替换为[]。但这是一场永无止境的战斗……如果某些字符串恰好包含 [ 怎么办?
猜你喜欢
  • 2011-12-15
  • 1970-01-01
  • 2010-10-07
相关资源
最近更新 更多