Регулярное выражение для анализа массива объектов JSON?
Я пытаюсь разобрать массив объектов JSON в массив строк в C#. Я могу извлечь массив из объекта JSON, но я не могу разбить строку массива на массив отдельных объектов.
У меня есть эта тестовая строка:
string json = "{items:[{id:0,name:\"Lorem Ipsum\"},{id:1,name"
+ ":\"Lorem Ipsum\"},{id:2,name:\"Lorem Ipsum\"}]}";
Прямо сейчас я использую следующие регулярные выражения прямо сейчас, чтобы разделить элементы на отдельные объекты. Пока это 2 отдельных регулярных выражения, пока я не исправлю проблему со вторым:
Regex arrayFinder = new Regex(@"\{items:\[(?<items>[^\]]*)\]\}"
, RegexOptions.ExplicitCapture);
Regex arrayParser = new Regex(@"((?<items>\{[^\}]\}),?)+"
, RegexOptions.ExplicitCapture);
arrayFinder
регулярное выражение работает так, как я ожидал, но по причинам, которые я не понимаю, arrayParser
регулярное выражение не работает вообще. Все, что я хочу сделать, это разделить отдельные элементы на их собственные строки, чтобы я получил такой список:
{id:0,name:"Lorem Ipsum"}
{id:1,name:"Lorem Ipsum"}
{id:2,name:"Lorem Ipsum"}
Является ли этот список string[]
массив или Group
или же Match
Коллекция не имеет значения, но я в тупик о том, как разделить объекты. С использованием arrayParser
и json
Строка, объявленная выше, я попробовал этот код, который я предположил, будет работать без удачи:
string json = "{items:[{id:0,name:\"Lorem Ipsum\"},{id:1,name"
+ ":\"Lorem Ipsum\"},{id:2,name:\"Lorem Ipsum\"}]}";
Regex arrayFinder = new Regex(@"\{items:\[(?<items>[^\]]*)\]\}"
, RegexOptions.ExplicitCapture);
Regex arrayParser = new Regex(@"((?<items>\{[^\}]\}),?)+"
, RegexOptions.ExplicitCapture);
string array = arrayFinder.Match(json).Groups["items"].Value;
// At this point the 'array' variable contains:
// {id:0,name:"Lorem Ipsum"},{id:1,name:"Lorem Ipsum"},{id:2,name:"Lorem Ipsum"}
// I would have expected one of these 2 lines to return
// the array of matches I'm looking for
CaptureCollection c = arrayParser.Match(array).Captures;
GroupCollection g = arrayParser.Match(array).Groups;
Кто-нибудь может увидеть, что я делаю не так? Я полностью застрял на этом.
5 ответов
Сбалансированные скобки - буквально пример учебника языка, который не может быть обработан с помощью регулярных выражений. JSON - это, по сути, сбалансированные скобки плюс куча других вещей, с фигурными скобками, замененными на скобки. В иерархии формальных языков JSON является контекстно-свободным языком. Регулярные выражения не могут анализировать контекстно-свободные языки.
В некоторых системах есть расширения для регулярных выражений, которые своего рода обрабатывают сбалансированные выражения. Тем не менее, они все уродливые хаки, они все непереносимы, и все они в конечном итоге являются неподходящим инструментом для работы.
В профессиональной работе вы почти всегда используете существующий JSON-анализатор. Если вы хотите бросить свой собственный в образовательных целях, то я бы предложил начать с простой арифметической грамматики, которая поддерживает + - * / (). (У JSON есть некоторые экранирующие правила, которые, хотя и не являются сложными, сделают вашу первую попытку сложнее, чем нужно.) По сути, вам необходимо:
- Разложи язык на алфавит символов
- Напишите контекстно-свободную грамматику в терминах тех символов, которые распознают язык
- Преобразуйте грамматику в нормальную форму Хомского, или достаточно близко, чтобы сделать шаг 5 легким
- Напишите лексер, который преобразует необработанный текст в ваш входной алфавит
- Напишите синтаксический анализатор рекурсивного спуска, который принимает выходные данные вашего лексера, анализирует их и выдает какой-то вывод
Это типичное задание на третий год обучения в CS почти в любом университете.
Следующий шаг - выяснить, насколько сложная строка JSON необходима для запуска переполнения стека в вашем рекурсивном парсере. Затем посмотрите на другие типы синтаксических анализаторов, которые можно написать, и вы поймете, почему любой, кому приходится анализировать язык без контекста в реальном мире, использует инструмент, такой как yacc или antlr, вместо того, чтобы писать анализатор вручную.
Если это больше обучения, чем вы искали, вы можете свободно использовать готовый JSON-анализатор, удовлетворенный тем, что вы узнали что-то важное и полезное: ограничения регулярных выражений.
Сбалансированные круглые скобки - буквально пример учебника языка, который не может быть обработан с помощью регулярных выражений
бла бла бла... проверить это:
arrayParser = "(?<Key>[\w]+)":"?(?<Value>([\s\w\d\.\\\-/:_]+(,[,\s\w\d\.\\\-/:_]+)?)+)"?
это работает для меня
если вы хотите сопоставить пустые значения, измените последний '+' на '*'
Вы используете.NET 3.5? Если это так, вы можете использовать DataContractJsonSerializer
разобрать это. Нет причин делать это самостоятельно.
Если вы не используете.NET 3.5, вы можете использовать Jayrock.
public Dictionary<string, string> ParseJSON(string s)
{
Regex r = new Regex("\"(?<Key>[\\w]*)\":\"?(?<Value>([\\s\\w\\d\\.\\\\\\-/:_\\+]+(,[,\\s\\w\\d\\.\\\\\\-/:_\\+]*)?)*)\"?");
MatchCollection mc = r.Matches(s);
Dictionary<string, string> json = new Dictionary<string, string>();
foreach (Match k in mc)
{
json.Add(k.Groups["Key"].Value, k.Groups["Value"].Value);
}
return json;
}
Эта функция реализует регулярное выражение Лукаша. Я только добавляю inclide + char в группу значений (потому что я использую это для разбора токена аутентификации live connect)
JSON, как правило, не может быть проанализирован с помощью регулярных выражений (некоторые чрезвычайно упрощенные варианты JSON могут, но тогда это не JSON, а что-то другое).
Вам нужен реальный парсер, чтобы правильно проанализировать JSON.
И вообще, почему вы вообще пытаетесь разобрать JSON? Есть множество библиотек, которые могут сделать это для вас, и гораздо лучше, чем ваш код. Зачем изобретать велосипед, когда за углом находится завод по производству колес с надписью FOSS над дверью?