我试图找到一个正则表达式来匹配嵌套 JSON 字符串表示的不同级别上的重复键。到目前为止,我所有的“解决方案”都遭受了灾难性的回溯。
该 JSON 字符串的示例如下所示:
d = {
"a": {
"b": {
"c": {
"d": "v1",
"key": "v2"
}
},
"c": {
"g": "v3",
"key": "v4"
},
"key": "v5"
}
}
key
的值就是目标。我的应用程序确实具有指向该键的所有对象名称。使用这些名称,我可以使用 for 循环来构建我的最终正则表达式。所以基本上我需要把零件放在中间。
例子:
如果我得到 "a"
和 "key"
,我可以构造以下内容:"a"[^}]*"key"
。这与我的字符串 d
中的第一个“key”相匹配,它的值为 v2。
不过,应该发生的是 "a"
+ "key"
匹配值为 v5 的键。当完整路径 "a"
+ "b"
+ "c"
+ "key 时,值为 v2 的键应该匹配"
进来了。这个例子中的最后一个例子是在 "a"
+ "c"
+ "key 时匹配键和值 v4 "
已给出。
所以最后一个的完整正则表达式看起来类似于:
"a"MATCH_EVERYTHING_IN_BETWEEN_REGEX"c"MATCH_EVERYTHING_IN_BETWEEN_REGEX"key":\s*(\[[^}]*?\]|".*?"|\d+\.*\d*)
明确地说,我正在寻找可以作为连接器插入的 MATCH_EVERYTHING_IN_BETWEEN_REGEX 表达式。这是为了确保它仅匹配我收到的路径的 key 。 JSON 字符串可以无限嵌套。
这是一个带有示例的在线正则表达式测试器: https://regex101.com/r/yNZ3wo/2
注意:
我知道这不是特定于 python 的,但我也很感谢在此上下文中的 python 提示。我考虑过构建自己的解析器,使用堆栈并计算 {
和 }
但在此之前我想确保没有简单的正则表达式解决方案。
编辑: 我知道 json 库,但这并不能解决我的问题,因为我正在编辑器窗口内的字符串表示中跟踪我的目标坐标。我不是在寻找值本身,我可以从关联的字典中访问它们。
最佳答案
这很难。一个可能的解决方案是使用
- 用于匹配嵌套大括号的递归正则表达式*
(?<="a": )({(?>[^{}]|(?1))*})
- 然后,继续使用垃圾桶方法在内部级别搜索键,即忽略整体匹配,只查看特定捕获组是否包含值
(此处 $2,根据需要添加组):
({(?>[^{}]|(?1))*})|"key":\s*"([^"]*?)"
代码示例:
import regex as re
test_str = ("{ \n"
" \"a\": { \n"
" \"b\": { \n"
" \"c\": { \n"
" \"d\": \"v1\", \n"
" \"key\": \"v2\" \n"
" } \n"
" }, \n"
" \"c\": { \n"
" \"g\": \"v3\", \n"
" \"key\": \"v4\" \n"
" }, \n"
" \"key\": \"v5\" \n"
" } \n"
" } \n"
"} \n")
regex = r"(?<=\"a\": )({(?>[^{}]|(?1))*})"
innerRegex = r"({(?>[^{}]|(?1))*})|\"key\":\s*\"([^\"]*?)\""
matches = re.finditer(regex, test_str, re.DOTALL)
for n, match in enumerate(matches):
n = n + 1
#print ("Match {n} was found at {start}-{end}: {match}".format(n = n, start = match.start(), end = match.end(), match = match.group()))
inner = match.group()[1:-1]
innerMatches = re.finditer(innerRegex, inner, re.DOTALL)
for m, innerMatch in enumerate(innerMatches):
#m = m + 1
if (innerMatch.groups()[1] is not None):
print ("Found at {start}-{end}: {group}".format(start = innerMatch.start(2), end = innerMatch.end(2), group = innerMatch.group(2)))
或者继续搜索下一层(上面没有显示)代码。
基本上,您将从 inner
继续以相同的方式从步骤 1 开始再次匹配(参见 demo ),例如:
(?<="c": )({(?>[^{}]|(?1))*})
这应该让您抢先一步。
*由于我们使用正则表达式递归,我们需要替代的 Python 正则表达式包。
关于python - 在 Python 中使用正则表达式匹配 JSON 键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50539399/