如何使用共享反向引用进行多次替换?

时间:2018-03-10 18:32:22

标签: regex pcre backreference capture-group

我需要进行一些数据转换以实现数据负载兼容性。嵌套的键:值对需要展平,并将其组ID添加到每个子数据之前。

我一直试图理解该页面 Repeating a Capturing Group vs. Capturing a Repeated Group但似乎无法绕过它。

到目前为止我的表达:

//Swap the two rightmost consecutive bits that are different
for (int i = 0; i < 64; i++) {
        if ((((x >> i) & 1) ^ ((x >> (i+1)) & 1)) == 1) {
            // then swap them or flip their bits
            int mask = (1 << i) | (1 << i + 1);
            x = x ^ mask;
            System.out.println("x = " + x);
            return;
        }
    }

工作样本:https://regex101.com/r/Wobej7/1

我知道使用一个或多个中间步骤可以简化流程,但此时我想知道它是否可能。

源数据示例:

"(?'group'[\w]+)": {\n((\s*"(?'key'[^"]+)": "(?'value'[^"]+)"(?:,\n)?)+)\n},?

期望的转型:

"g1": {
  "k1": "v1",
  "k2": "v2",
  "k3": "v3"
},
"g2": {
  "k4": "v4",
  "k5": "v5",
  "k6": "v6"
},
"g3": {
  "k7": "v7",
  "k8": "v8",
  "k9": "v9"
}

1 个答案:

答案 0 :(得分:0)

TL; DR

第1步

搜索:

("[^"]+"):\s*{[^}]*},?\K

替换为\1

Live demo

第2步

搜索:

(?:"[^"]+":\s*{|\G(?!\A))\s*("[^"]+"):\s*((?1))(?=[^}]*},?((?1)))(?|(,)|\s*}(,?).*\R*)

替换为:

{\3,\1,\2}\4\n

Live demo

整体哲学

出于不同的原因,这不是一个单行的正则表达式解决方案。最重要的一点是我们既不能存储匹配的一部分供以后引用,也不能在PCRE中进行无限的观察。但幸运的是,大多数类似的问题可以分两步完成。

第一步应该是将组名移到{...}块的末尾。这样,每次我们想要将匹配转换为单行输出时,我们都可以拥有组名。

("[^"]+"):\s*{[^}]*},?\K
  • (开始捕获组#1
    • "[^"]+"匹配群组名称
  • ) CG#1结束
  • :\s*{群组名称应位于一堆其他角色之前
  • [^}]*},?我们必须进一步到块结束
  • \K扔掉目前匹配的所有内容

我们在第一个捕获组中保留了我们的组名,并且必须用它替换整个匹配:

\1

现在这样一个块:

"g1": {
  .
  .
  .
},

看起来像这样:

"g1": {
  .
  .
  .
},"g1"

下一步是匹配每个块的键:值对,并在块的末尾捕获最近添加的组名。

(?:"[^"]+":\s*{|\G(?!\A))\s*("[^"]+"):\s*((?1))(?=[^}]*},?((?1)))(?|(,)|\s*}(,?).*\R*)
  • (?:启动非捕获组
    • "[^"]+"尝试匹配群组名称
    • :\s*{一个群组名称应该来自一堆其他角色
    • |
    • \G(?!\A)从上一场比赛继续
  • ) NCG结束
  • \s*("[^"]+"):\s*((?1))然后尝试匹配并捕获密钥:值对
  • (?=[^}]*},?((?1)))在块结束时同时匹配并捕获组名称
  • (?|(,)|\s*}(,?).*\R*)匹配剩余字符,例如逗号,大括号或换行符

这种方式在每次成功试用正则表达式引擎时,我们有四个捕获的数据,他们的订单是关键:

{\3,\1,\2}\4\n
  • \3组名(在块末尾添加的名称)
  • \1密钥
  • \2价值
  • \4逗号(可能在那里或可能没有)