【问题标题】:Matching JSON with a regular expression用正则表达式匹配 JSON
【发布时间】:2017-03-20 06:14:32
【问题描述】:

我有一个包含许多对象字面量的 JavaScript 文件:

// lots of irrelevant code
oneParticularFunction({
    key1: "string value",
    key2: 12345,
    key3: "strings which may contain ({ arbitrary characters })"
});
// more irrelevant code

我需要编写一些 Python 代码来提取这些文字。

我的第一次尝试是正则表达式oneParticularFunction\(\{(.*?)\}\);。但如果文字包含“})”,则会失败。

由于我知道对象将是有效 JavaScript 文件中的有效 JSON(匹配的引号、大括号等),有没有更优雅的方法来提取它们?

(换句话说,困难在于删除所有其他我不关心的 JavaScript 代码。)

编辑:最后,我对任何不包含子对象的对象使用了正则表达式...

oneParticularFunction\((\{([^"}]*"[^"]*"[^"}]*)*?[^"]*?\})\);

...并手动跟踪打开/关闭大括号以进行任何嵌套。

【问题讨论】:

  • 在python中使用其中一个json解码器怎么样?然后你迭代每个键值对。
  • @elfan 我希望使用json,但我需要先摆脱所有周围的JavaScript。
  • 如果代码看起来像您的示例,您可以实现 oneParticularFunction() JavaScript 函数的 Python 版本,然后尝试使用 @ 从文件中执行代码片段(这只是一个函数调用) 987654326@。如果成功,那么您可以从传递给函数的参数中提取值(这将是一个 Python 字典对象)。
  • @martineau 这是一个漂亮的 hack,但不幸的是 Python 坚持在字典键周围加上引号,而 JSON 没有。

标签: javascript python json regex


【解决方案1】:

为什么不编写一个状态机来读取 { 并在每个 { 上增加一个计数器并随着每个 } 减少它,所以当它再次达到 0 时,取出中间的所有字符并使用 python 中的 json 解析器来检查它是否是否有效?这样,您可以获得语法错误的好处,而不是从正则表达式中简单地匹配不匹配(请记住 python 是免费的,因此不可能出现误报)。

【讨论】:

  • 这绝对是个不错的选择;我只是希望我忽略了一些更 Pythonic 的方式。
  • 我已经做 python 几年了...我会说这是一个不错的选择,但请稍等一下,看看我们是否能得到更好的答案。
  • 状态机方法还必须能够处理 JavaScript 文字中的字符串,理论上这些字符串本身可以包含 {} 字符。你是什​​么意思 Python 没有这些字符?这是在 Python 代码中定义文字字典的常用方法。
  • 我的意思是它们不用于流量控制
【解决方案2】:

正则表达式代码:

(?<=(?:\s\"))[\s\S]+?(?=\")|(?<=(?:\s))\d+

https://regex101.com/r/bfNkvF/3 正则表达式的实时示例

在 Python 中使用之前的正则表达式:

import re
text = '''oneParticularFunction({
key1: "string value",
key2: 12345,
key3: "strings which may contain ({ arbitrary characters })"
});'''
for m in re.finditer(r"(?<=(:\s\"))[\s\S]+?(?=\")|(?<=(:\s))\d+", text):
    print('%s' % (m.group(0)))

我在pythontutor 上测试了这段代码,它似乎可以工作。您可以将其复制并粘贴到那里。让我知道它是否适用于其他对象文字。

【讨论】:

  • 一旦我提取了一个特定的实例,这将非常有效,但如果有其他函数调用或对 oneParticularFunction 的多次调用,它似乎会将它们组合在一起。但是现在我已经被介绍了前瞻和后瞻,我认为这将是解决方案。谢谢!
【解决方案3】:

我能够使用它从字符串中删除所有括号,而不会消除或不匹配外部的 '({' and '})'

while True:
    newstring = re.sub(r'(\(\{.*)\{([^{}]*)\}(.*\}\))', r'\1\2\3', mystring)
    if newstring == mystring:
        break
    mystring = newstring

这里有 3 个组(我知道,很难说)。第一个是(\(\{.*)。这会找到您的({,然后找到它之后的任何内容,直到找到最里面的{

我们知道它是最里面的{,因为第二组([^{}]*)。这将匹配不是{} 的任何内容。

然后,(.*\}\)) 查找最里面的} 之后的所有内容。

通过将这三个组重新组合在一起来替换整个匹配项({} 被排除在外)。它会重复此操作,直到找不到要替换的匹配大括号为止。

如果你也想替换(),你可以修改为

newstring = re.sub(r'(\(\{.*)(\{|\()([^{}()]*)(\}|\))(.*\}\))', r'\1\3\5', mystring)

【讨论】:

    猜你喜欢
    • 2022-08-17
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    • 2018-04-23
    • 1970-01-01
    • 2019-03-30
    • 2011-05-01
    相关资源
    最近更新 更多