【问题标题】:REGEX in Python: what's wrong with (?<!\\)\".+(?<!\\)\"?Python 中的正则表达式:(?<!\\)\".+(?<!\\)\" 有什么问题?
【发布时间】:2015-02-12 05:24:20
【问题描述】:

试图解析引号内的 JSON 键名,包括转义的引号。 我的想法是:在引号 not 之间取任何东西,前缀为 \

(?<!\\)\".+(?<!\\)\"

(?&lt;!\\)\" 应该筛选 " 但不是 \" 但 Python 抱怨括号不平衡。 如果我使用(?&lt;!\\\)\" Python 很高兴,但这不起作用:

re.findall('(?<!\\\)\".+(?<!\\\)\"','"this is \"the\". key"."and this.is.the.child"')

线索:

['"this is "the". key"."and this.is.the.child"']

当我期望时:

['"this is "the". key"', '"and this.is.the.child"']

在用 " 括起来的点处分割,不要转义。

我觉得我需要一个“任何东西,但没有转义双引号”在中间,但如果 [^"] 筛选除双引号外的任何内容,我不知道如何在将字符作为文字的 [ ] 集中否定 (?&lt;!\\\)\" 表达式。 我想要[^(?&lt;!\\\)\"] 之类的东西,但这不起作用。

我尝试了 [[^"]|(\")]+ (除了双引号或 \" 之外的任何东西),但这似乎也不起作用......

似乎找不到正确的方法来执行此操作... 有什么想法吗?

感谢您的帮助

编辑:

我的真正目标是能够拆分完整的“文本”JSON 键名,以将它们转换为仅包含字母数字的值。转换在这里无关紧要,但目标是拆分键以正确表示层次结构。键是文本形式。

编辑 2:

即使 OmnipotentEntity 很可能是正确的,编写解析器也必须等待.. 下面的这个解决方案不支持他的 cmets 中指出的 "\" 或 "\\" 情况。

我和

"(?:\\"|[^"])*?"|(?<=\.)[^".]+?(?=\.)|^[^".]+?(?=\.)|(?<=\.)[^".]+?$

灵感来自 Avinash Raj 的回答 但添加了对不包含在双引号中的键的支持: 没有以 . 结尾的行开头的引号。 。钥匙。 和 .lastkey 当用相同的正则表达式替换 [empty] 时,应该找到比找到的字符串数少 1 个元素,否则会出错。 像 .. outside "" 之类的东西将无法通过该测试

【问题讨论】:

  • 虽然 JSON 是 LL(1) 语言,但它不是常规语言。使用正则表达式你可能会糊涂,但我建议编写一个实际的解析器,而不是依赖正则表达式,因为这样更容易推理和指出错误。

标签: python regex json


【解决方案1】:

从根本上说,在一般情况下,使用正则表达式来匹配带引号的字符串是不可能的。 JSON 不是正则语言(所有正则语言都是 LL(1) 但不是所有 LL(1) 语言都是正则,JSON 就是其中之一),所以它不能被正则表达式匹配。

例如,Avinash Raj 的正则表达式 (?&lt;!\\)".*?(?&lt;!\\)""\\" 的情况下失败。因为引号前面是\,但反斜杠不能用作转义符。但是你不能特例这种情况,因为那样"\\\"" 会失败。如果你是这种情况的特殊情况,你可以使用 4 \ 然后 5 \ 等等。

Lookbehinds 不是标准正则表达式的一部分,因此它们可以匹配更多的语法而不是简单的正则表达式。因此,您可能会想出一个适用于这种情况的正则表达式。但是,我建议改为编写解析器,它们对于 LL(1) 语法很容易做到。它将更容易、更容易理解、更不脆弱,并为您提供更多处理不符合标准的 JSON 的能力,并让您能够在这种情况下编写更好的诊断消息。

【讨论】:

  • 你有任何关于如何编写解析器的例子吗?你说这很容易,但我不得不承认我不知道从哪里开始。逐个字符解析,是这个意思吗?
  • 基本上是的。逐个字符地进行并保持解析器的状态。 LL(1) 意味着您可以在一次通过时进行解析,只需 1 个前瞻字符。查看维基百科页面以获取示例解析器:en.wikipedia.org/wiki/LL_parser#Parser_implementation_in_Python
【解决方案2】:

尝试将您的正则表达式定义为原始字符串表示法。

>>> s = r'"this is \"the\". key"."and this.is.the.child"'
>>> re.findall(r'"(?:\\"|[^"])*?"', s)
['"this is \\"the\\". key"', '"and this.is.the.child"']

DEMO

>>> re.findall(r'(?<!\\)".*?(?<!\\)"', s)
['"this is \\"the\\". key"', '"and this.is.the.child"']
  • (?&lt;!\\) 调用了否定的lookbehind,它断言匹配不会以反斜杠开头。

  • " 匹配双引号。

  • .*?(?&lt;!\\)" 非贪婪匹配所有字符,直到双引号前面没有反斜杠。

【讨论】:

  • "\\" 怎么样? "\\\" 怎么样?
  • 这不是操作员要求的。如果您有任何澄清,请向操作员询问。
  • OP 要求提供一个匹配有效 JSON 密钥的正则表达式。 "\\" 是一个有效的 json 键。 "\\" 与您的正则表达式不匹配
猜你喜欢
  • 2018-09-06
  • 2013-09-13
  • 2012-02-24
  • 1970-01-01
相关资源
最近更新 更多