【问题标题】:Find JSON strings in a string在字符串中查找 JSON 字符串
【发布时间】:2014-03-26 12:34:21
【问题描述】:

我正在寻找一种在字符串中查找 JSON 数据的方法。把它想象成 wordpress 简码。我认为最好的方法是使用正则表达式。我不想解析 JSON,只想找到所有出现的地方。

正则表达式中是否有办法匹配括号数?目前我在嵌套对象时遇到了这个问题。

快速演示示例:

This is a funny text about stuff,
look at this product {"action":"product","options":{...}}.
More Text is to come and another JSON string
{"action":"review","options":{...}}

因此,我想要两个 JSON 字符串。 谢谢!

【问题讨论】:

  • 看到这个问题Regex to validate JSON
  • 我认为这里更大的问题是为什么将 JSON 字符串嵌入到纯文本块中?我认为改进设计可能是比尝试构建正则表达式来在野外查找 JSON 子字符串更好的方法。
  • 正则表达式中是否有办法匹配括号数? -> 不,正则表达式不是为此而生的。为什么不使用json_decode 并解析结果数组以获得所需的数据?
  • 您意识到42 将是有效的JSON? "Hi There!" 也一样吗?除非您将 json 限制为仅编码对象,否则几乎不可能检测到所有有效的 json 形式。
  • 我想将这些 JSON 对象用作 wordpress 中的简码。 wordpress 的实现很混乱,至少我是这么认为的。为了给我喜欢运行的函数提供数据,我认为 JSON 是最好的方法。作为一种解决方法,我可以做类似 [[{json}]] 的事情并匹配 [[...]]。但是我想让它尽可能简单。

标签: php regex json


【解决方案1】:

从给定文本中提取 JSON 字符串

由于您正在寻找一个简单的解决方案,您可以使用以下利用递归的正则表达式来解决匹配括号集的问题。它递归匹配 {} 之间的所有内容。

不过,您应该注意,这并不能保证适用于所有可能的情况。它仅作为一种快速的 JSON 字符串提取方法。

$pattern = '
/
\{              # { character
    (?:         # non-capturing group
        [^{}]   # anything that is not a { or }
        |       # OR
        (?R)    # recurses the entire pattern
    )*          # previous group zero or more times
\}              # } character
/x
';

preg_match_all($pattern, $text, $matches);
print_r($matches[0]);

输出:

Array
(
    [0] => {"action":"product","options":{...}}
    [1] => {"action":"review","options":{...}}
)

Regex101 Demo


验证 JSON 字符串

在 PHP 中,了解 JSON 字符串是否有效的唯一方法是应用 json_decode()。如果解析器理解 JSON 字符串并且符合定义的标准,json_decode() 将创建 JSON 字符串的对象/数组表示。

如果您想过滤掉那些无效的 JSON,那么您可以使用带有回调函数的 array_filter()

function isValidJSON($string) {
    json_decode($string);
    return (json_last_error() == JSON_ERROR_NONE);
}

$valid_jsons_arr = array_filter($matches[0], 'isValidJSON');

Online demo

【讨论】:

  • 由于 Java 没有递归步骤,我只使用了该模式 3 次:\{(?:[^{}]|(\{(?:[^{}]|(\{[^ {}]*\}))*\}))*\} 对我来说已经足够了......但是很老套......
  • 这种方法不起作用的一种情况是字符串中有大括号。例如:{"text":"abc { def"}
【解决方案2】:

Javascript 人正在寻找类似的正则表达式。 javascript、python 和其他语言不支持递归正则表达式模式的 (?R)。

注意:不是一对一替换。

 \{(?:[^{}]|(?R))*\} # PCRE Supported Regex

步骤:

  1. 复制整个正则表达式并替换复制字符串的?R 示例
  • 1 级 json => \{(?:[^{}]|(?R))*\} => \{(?:[^{}]|())*\}
  • 2 级 json => \{(?:[^{}]|(\{(?:[^{}]|(?R))*\}))*\} => \{(?:[^{}]|(\{(?:[^{}]|())*\}))*\}
  • n 级 json => \{(?:[^{}]|(?<n times>))*\}
  1. 当决定在某个级别停止时,将 ?R 替换为空白字符串。

完成。

【讨论】:

    【解决方案3】:

    我会添加一个* 来包含嵌套对象:

    {(?:[^{}]*|(?R))*}
    

    查看Demo

    【讨论】:

      【解决方案4】:

      添加到建议 ?R 进行递归的答案: 如果您还想在正则表达式字符串中匹配其他内容,而不仅仅是 json 对象(即:一个 json 对象后跟一个字符串,如key: {jsonobject}),那么您希望仅递归 json 规则:

      (?<j>\{(?:[^{}]|(?&j))*\})
      

      我在这个例子中使用named subpatterns。注意?&lt;j&gt;(?&amp;j),它们定义了子模式,并分别引用它)。 有了这个,您可以匹配以下作为示例:

      • 只匹配后面跟着“ERROR: ”的json对象:
      ERROR: (?<j>\{(?:[^{}]|(?&j))*\})
      
      ERROR: {"some": "info"}     # will match
      INFO: {"some": "info"}      # won't match
      

      参见regex101上的示例

      【讨论】:

        猜你喜欢
        • 2011-01-11
        • 2020-10-09
        • 1970-01-01
        • 2011-07-13
        • 2016-01-26
        • 2014-02-04
        相关资源
        最近更新 更多