首页 > 解决方案 > PHP/Regex: Parse JSON in string

问题描述

I'm trying to find simple key-value-pairs in strings, given as JSON-objects, while using preg_replace_callback().

Unfortunately, the values given can be of type string, number, boolean, null, array - and worst of all - objects. My own attempts solving this problem resulted in either an incomplete selection or over-selecting multiple JSON occurances as one.

Here the things i tried:

String:
text text {"key":{"key":"value"}} text

Regex:
\{"(.+?)"\:(.+?)\}

Match:
{"key":"value"

Above: This ignores the inner }-bracket

String:
text text {"key":{"key":"value"}} text

Regex:
\{"(.+?)"\:(.+)\}

Match:
{"key":"value"}

Above: This would (theoretically) work, but when having multiple JSON occurances, i get:

{"key":"value"}} {"key":{"key":"value"}

Next attempt:

String:
text text {"key":{"key":"value"}} {"key":{"key":"value"}} text

Regex:
\{"(.+?)"\:(?:(\{(?:.+?)\})|(?:")?(.+?)(?:")?)\}

Match:
{"key":"value"}

Above: Again, that would theoreticcally work. But when taking, for example, the following string:

text text {"key":{"key":{"key":"value"}}} text

The result is...

{"key":{"key":"value"}

Missing one bracket

标签: phpjsonregex

解决方案


PCRE supports recursive matching for that kind of nested structures. Here is a demo:

$data = 'text text 
  {"key":{"key":"value{1}","key2":false}} 
  {"key":{"key":"value2"}} 
  {"key":{"key":{"key":"value3"}}} text';

$pattern = '(
    \{ # JSON object start
        ( 
            \s*
            "[^"]+"                  # key
            \s*:\s*                  # colon
            (
                                     # value
                (?: 
                    "[^"]+" |        # string
                    \d+(?:\.\d+)? |  # number
                    true |
                    false |
                    null
                ) | 
                (?R)                 # pattern recursion
            )
            \s*
            ,?                       # comma
        )* 
    \} # JSON object end
)x';
preg_replace_callback(
    $pattern,
    function ($match) {
        var_dump(json_decode($match[0]));
    },
    $data
);

推荐阅读