9

我正在实现某种解析器,我需要定位和反序列化嵌入到其他半结构化数据中的 json 对象。我使用了正则表达式:

\\{\\s*title.*?\\}

定位对象

{title:'Title'}

但它不适用于嵌套对象,因为表达式仅匹配首先找到的右花括号。为了

{title:'Title',{data:'Data'}}

它匹配

{title:'Title',{data:'Data'}

所以字符串对于反序列化变得无效。我知道有一个贪婪的业务正在考虑,但我不熟悉正则表达式。您能否帮我扩展表达式以使用所有可用的右大括号。

更新:

需要明确的是,这是从嵌入 JSON 的 HTML+JS 等半结构化数据中提取 JSON 数据的尝试。我正在使用 GSon JAVA lib 来实际解析提取的 JSON。

4

4 回答 4

6

正如其他人所建议的那样,一个成熟的 JSON 解析器可能是要走的路。如果要匹配上面简单示例中的键值对,可以使用:

(?<=\{)\s*[^{]*?(?=[\},])

对于输入字符串

{title:'Title',  {data:'Data', {foo: 'Bar'}}}

这匹配:

 1. title:'Title'
 2. data:'Data'
 3. foo: 'Bar'
于 2013-07-22T12:04:58.313 回答
6

这个递归 Perl/PCRE 正则表达式应该能够匹配任何有效的 JSON 或 JSON5 对象,包括嵌套对象和边缘情况,例如 JSON 字符串中的大括号或 JSON5 注释:

/(\{(?:(?>[^{}"'\/]+)|(?>"(?:(?>[^\\"]+)|\\.)*")|(?>'(?:(?>[^\\']+)|\\.)*')|(?>\/\/.*\n)|(?>\/\*.*?\*\/)|(?-1))*\})/

当然,这有点难读,所以你可能更喜欢注释版本:

m{
  (                               # Begin capture group (matching a JSON object).
    \{                              # Match opening brace for JSON object.
    (?:                             # Begin non-capturing group to contain alternations.
      (?>[^{}"'\/]+)                  # Match a non-empty string which contains no braces, quotes or slashes, without backtracking.
    |                               # Alternation; next alternative follows.
      (?>"(?:(?>[^\\"]+)|\\.)*")      # Match a double-quoted JSON string, without backtracking.
    |                               # Alternation; next alternative follows.
      (?>'(?:(?>[^\\']+)|\\.)*')      # Match a single-quoted JSON5 string, without backtracking.
    |                               # Alternation; next alternative follows.
      (?>\/\/.*\n)                    # Match a single-line JSON5 comment, without backtracking.
    |                               # Alternation; next alternative follows.
      (?>\/\*.*?\*\/)                 # Match a multi-line JSON5 comment, without backtracking.
    |                               # Alternation; next alternative follows.
      (?-1)                           # Recurse to most recent capture group, to match a nested JSON object.
    )*                              # End of non-capturing group; match zero or more repetitions of this group.
    \}                              # Match closing brace for JSON object.
  )                               # End of capture group (matching a JSON object).
}x
于 2020-03-06T02:27:43.483 回答
3

感谢@Sanjay T. Sharma 向我指出“大括号匹配”,因为我最终对贪婪表达有了一些了解,也感谢其他人最初说我不应该做的事情。幸运的是,结果证明使用贪婪的表达式是可以的

\\{\s*title.*\\}

因为右括号之间没有非 JSON 数据。

于 2013-07-22T12:10:23.567 回答
1

这绝对是可怕的,我不敢相信我真的把我的名字放到了这个解决方案中,但是你能不能找到{Javascript 块中的第一个字符并尝试通过适当的 JSON 解析库来解析剩余的字符?如果它有效,你就有了比赛。如果没有,请继续阅读直到下一个{字符并重新开始。

那里有一些问题,但它们可能可以解决:

  • 您需要能够识别 Javascript 块。大多数语言都有从 HTML 到 DOM 的库(我是Cyber​​neko for Java 的忠实粉丝),这样可以很容易地专注于<script>...</script>块。
  • 您的 JSON 解析库需要在发现错误后立即停止使用流中的字符,并且在发生错误时不需要关闭流。

一个改进是,一旦你找到了第一个{,去寻找匹配}的那个(一个简单的计数器,当你找到 a 时它会增加,当你找到 a{时会减少它}应该做的伎俩)。尝试将生成的字符串解析为 JSON。迭代直到它起作用或者你已经用完了可能的块。

这是丑陋的,骇人听闻的,永远不应该将其用于生产代码。不过,我的印象是你只需要它来进行批处理,这就是我什至建议它的原因。

于 2013-07-22T12:08:44.540 回答