Да, распространенным заблуждением является то, что регулярные выражения могут соответствовать только обычным языкам . Фактически, функции PCRE могут соответствовать гораздо большему, чем обычные языки , они могут соответствовать даже некоторым неконтекстно-свободным языкам! В статье Википедии о RegExps есть специальный раздел об этом.
JSON может быть распознан с использованием PCRE несколькими способами! @mario показал одно отличное решение, используя именованные подшаблоны и обратные ссылки . Затем он отметил, что должно быть решение с использованием рекурсивных шаблонов (?R)
. Вот пример такого регулярного выражения, написанного на PHP:
$regexString = '"([^"\\\\]*|\\\\["\\\\bfnrt\/]|\\\\u[0-9a-f]{4})*"';
$regexNumber = '-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?';
$regexBoolean= 'true|false|null'; // these are actually copied from Mario's answer
$regex = '/\A('.$regexString.'|'.$regexNumber.'|'.$regexBoolean.'|'; //string, number, boolean
$regex.= '\[(?:(?1)(?:,(?1))*)?\s*\]|'; //arrays
$regex.= '\{(?:\s*'.$regexString.'\s*:(?1)(?:,\s*'.$regexString.'\s*:(?1))*)?\s*\}'; //objects
$regex.= ')\Z/is';
Я использую (?1)
вместо (?R)
, поскольку последний ссылается на шаблон весь , но у нас есть последовательности \A
и \Z
, которые не должны использоваться внутри подшаблонов. (?1)
ссылается на регулярное выражение, помеченное крайними круглыми скобками (поэтому крайний ( )
не начинается с ?:
). Таким образом, RegExp становится длиной 268 символов:)
/\A("([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"|-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?|true|false|null|\[(?:(?1)(?:,(?1))*)?\s*\]|\{(?:\s*"([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"\s*:(?1)(?:,\s*"([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"\s*:(?1))*)?\s*\})\Z/is
В любом случае, это следует рассматривать как «демонстрацию технологии», а не как практическое решение. В PHP я проверю строку JSON с помощью вызова функции json_decode()
(точно так же, как заметил @Epcylon). Если я собираюсь использовать этот JSON (если он проверен), то это лучший метод.