【问题标题】:Regex: Is it possible to do a substitution within a capture group?正则表达式:是否可以在捕获组内进行替换?
【发布时间】:2018-09-12 09:44:23
【问题描述】:

我有这一行 JSON 文本:

{"schemaText":{"fields":[{"name":"AX_SND_TYPE","type":"string"},{"name":"BWORK","type":"int"}],"name":"XXXSchema","type":"record"},"description":"Autogenerated by NiFi"}

可以看出有一个名为“schemaText”的属性包含一个对象,我想将其转换为字符串,所以我需要做的“唯一”事情是在属性的开头和结尾添加引号并转义里面的引号。

使用下面的正则表达式(不是我的正则表达式知识真的很低),我可以做第一步:

({"schemaText":)(\{"fields":\[.*)(,"description.*)

使用替换

$1"$2"$3

给出结果:

{"schemaText":"{"fields":[{"name":"AX_SND_TYPE","type":"string"},{"name":"BWORK","type":"int"}],"name":"XXXSchema","type":"record"}","description":"Autogenerated by NiFi"}

但仍然要转义引号才能得到这个:

{"schemaText":"{\"fields\":[{\"name\":\"AX_SND_TYPE\",\"type\":\"string\"},{\"name\":\"BWORK\",\"type\":\"int\"}],"name":"XXXSchema","type":"record"}","description":"Autogenerated by NiFi"}

即具有有效的 JSON 格式。

问题是:有没有办法在同一个正则表达式中转义 $2 捕获组内的引号?

提前致谢。

【问题讨论】:

  • 你必须为此使用正则表达式吗?您可以不使用 JSON 解析器按您的意愿对不同部分进行字符串化/对象化吗?
  • 是的,只有正则表达式,目前我有一个代码方法,但关键是如果可能的话,只能使用正则表达式来解决它。
  • Regex 不会为您转义字符串。您需要替换反斜杠
  • @cricket-007 不确定您是否阅读并理解您的观点,必须转义的是属性 schemaText 的引号,以便能够将其发布到架构注册表,转义所有引号正则表达式在这个例子中很简单:regex101.com/r/QNtqYy/1

标签: json regex avro confluent-schema-registry


【解决方案1】:

您的问题的答案是否定的,这是不可能的。你真的想在一个正则表达式中做两个不同的、不相关的替换。这是正则表达式引擎不支持的功能。

考虑一下:您的第一个要求是引擎对整个文本(引号)执行替换,然后,对于您的第二个要求,引擎必须以某种方式回溯并对可能或可能尚未更改:例如:它需要对已替换的文本执行新匹配,这取决于第一次替换所做的事情,甚至可能不再存在!

如您所说,如果您已经有一种可行的方法,请保留它。单个正则表达式根本不适合您尝试做的事情。

【讨论】:

  • 对不起,但这并不完全正确,正如我所写的,引号只能在捕获组内替换,实际上问题是:可以在捕获组内执行替换吗?
  • @ÓscarAndreu 如果我不清楚,我很抱歉。通过尝试以这种方式限制替换,您真正在做的就是我所描述的。我们倾向于认为正则表达式是非常复杂的软件,但事实并非如此,而且它们有一些警告。其中之一是正则表达式引擎是single-pass:除了不是真正匹配且无法捕获的lookaheads 和lookbehinds,regex 引擎总是从左到右读取并且从不回溯.
  • 替换意味着:删除所有匹配的文本,并将其粘贴到它的位置。当替换插入时,没有回头路。为了以某种方式替换由$2 引用生成的文本,引擎必须回溯替换的文本,这需要新的匹配。我向你断言,引擎不会那样做。
【解决方案2】:

我建议使用代码来解决这个问题,例如使用原生 JavaScript:

let json = '{"schemaText":{"fields":[{"name":"AX_SND_TYPE","type":"string"},{"name":"BWORK","type":"int"}],"name":"XXXSchema","type":"record"},"description":"Autogenerated by NiFi"}';

let obj = JSON.parse(json);
let schemaTextAsString = JSON.stringify(obj.schemaText)
obj.schemaText = schemaTextAsString

var result = JSON.stringify(obj)

你可以看到这个工作here

请注意,在您想要的输出中,您没有转义 schemaText 名称字段中的引号,但是这段代码可以。

最后每当我使用正则表达式时,我都会想起这篇经典文章"Regular Expressions: Now You Have Two Problems"

【讨论】:

  • 啊,我可以看到您使用的是不支持“开箱即用”javascript 的 Avro。我可以看到虽然github.com/mtth/avsc 有一个JS 客户端。如果这个答案与你无关,我仍然建议使用类似的方法而不是纯正则表达式来解决这个问题。
  • 嗨,本,感谢您的回复。我目前正在使用 javascript 来解决问题,但问题是是否可以在捕获组内进行替换,只有正则表达式。
【解决方案3】:

仅供参考,您实际上可以在应该发生替换的每个位置匹配,使用如下表达式:

/({"schemaText":)|}(,"description")(.*)|([^"]*)"/g

正如其他人所提到的,唯一的问题是你想做的不仅仅是比赛;您想执行“条件替换”,因为不存在一个涵盖所有 3 种情况的单一替换(在引号前插入 ",在引号前插入 \,并在结尾插入 @987654324 @)。

您实际上可以通过一个 replace() 调用来完成此操作:

var test = "{\"schemaText\":{\"fields\":[{\"name\":\"AX_SND_TYPE\",\"type\":\"string\"},{\"name\":\"BWORK\",\"type\":\"int\"}],\"name\":\"XXXSchema\",\"type\":\"record\"},\"description\":\"Autogenerated by NiFi\"}";
window.alert(test.replace(/({"schemaText":)|}(,"description")(.*)|([^"]*)"/g, function(a,b,c,d,e){ return (b=="{\"schemaText\":"?b+"\"":(c==",\"description\""?"}\""+c+d:e+"\\\"")) })));

所以它在技术上是“相同的正则表达式”,但替换参数使用内联函数作为替换而不是静态字符串。

【讨论】:

    猜你喜欢
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 2013-06-27
    • 2014-06-19
    • 2010-11-19
    • 1970-01-01
    相关资源
    最近更新 更多