正则表达式:是否可以在捕获组内进行替换?
Regex: Is it possible to do a substitution within a capture group?
我有这一行JSON文本:
{"schemaText":{"fields":[{"name":"AX_SND_TYPE","type":"string"},{"name":"BWORK","type":"int"}],"name":"XXXSchema","type":"record"},"description":"Autogenerated by NiFi"}
可以看出有一个叫做"schemaText"的属性包含了一个对象,我想把它转换成一个字符串,所以我需要做的'only'事情是在 属性 的开头和结尾添加引号并转义里面的引号。
使用下面的正则表达式(并不是说我的正则表达式知识真的很低),我能够完成第一步:
({"schemaText":)(\{"fields":\[.*)(,"description.*)
使用替换
""
给出结果:
{"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 捕获组内的引号?
提前致谢。
我建议使用代码解决这个问题,例如香草 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"!
你的问题的答案是否定的,这是不可能的。您实际上是在尝试在单个正则表达式中执行两个不同的、不相关的替换。这是一个正则表达式引擎不支持的功能。
想一想:您的第一个要求是让引擎对整个文本(引号)执行替换,然后,对于您的第二个要求,引擎必须以某种方式回溯并对文本执行更多替换可能已经更改,也可能没有更改:例如:它需要对已经替换的文本执行新的匹配,根据第一次替换的内容,该文本甚至可能不再存在!
如果像您所说的那样,您已经有了行之有效的方法,请保留它。单个正则表达式根本不适合您要执行的操作。
仅供参考,您实际上可以 匹配 在每个应该发生替换的位置,使用如下表达式:
/({"schemaText":)|}(,"description")(.*)|([^"]*)"/g
正如其他人所提到的,唯一的问题是您想要做的不仅仅是匹配;你想执行 "conditional replacement" 因为不存在一个单一的包罗万象的替换来覆盖你正在处理的所有 3 个案例(插入开始 "
,在引号前插入 \
,并插入结尾 "
)。
实际上,您只需调用一次 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+"\\"")) })));
所以它在技术上是 "the same regex",但是替换参数使用内联函数作为替换而不是静态字符串。
我有这一行JSON文本:
{"schemaText":{"fields":[{"name":"AX_SND_TYPE","type":"string"},{"name":"BWORK","type":"int"}],"name":"XXXSchema","type":"record"},"description":"Autogenerated by NiFi"}
可以看出有一个叫做"schemaText"的属性包含了一个对象,我想把它转换成一个字符串,所以我需要做的'only'事情是在 属性 的开头和结尾添加引号并转义里面的引号。
使用下面的正则表达式(并不是说我的正则表达式知识真的很低),我能够完成第一步:
({"schemaText":)(\{"fields":\[.*)(,"description.*)
使用替换
""
给出结果:
{"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 捕获组内的引号?
提前致谢。
我建议使用代码解决这个问题,例如香草 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"!
你的问题的答案是否定的,这是不可能的。您实际上是在尝试在单个正则表达式中执行两个不同的、不相关的替换。这是一个正则表达式引擎不支持的功能。
想一想:您的第一个要求是让引擎对整个文本(引号)执行替换,然后,对于您的第二个要求,引擎必须以某种方式回溯并对文本执行更多替换可能已经更改,也可能没有更改:例如:它需要对已经替换的文本执行新的匹配,根据第一次替换的内容,该文本甚至可能不再存在!
如果像您所说的那样,您已经有了行之有效的方法,请保留它。单个正则表达式根本不适合您要执行的操作。
仅供参考,您实际上可以 匹配 在每个应该发生替换的位置,使用如下表达式:
/({"schemaText":)|}(,"description")(.*)|([^"]*)"/g
正如其他人所提到的,唯一的问题是您想要做的不仅仅是匹配;你想执行 "conditional replacement" 因为不存在一个单一的包罗万象的替换来覆盖你正在处理的所有 3 个案例(插入开始 "
,在引号前插入 \
,并插入结尾 "
)。
实际上,您只需调用一次 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+"\\"")) })));
所以它在技术上是 "the same regex",但是替换参数使用内联函数作为替换而不是静态字符串。