Регулярное выражение для анализа массива объектов JSON?

StackOverflow https://stackoverflow.com/questions/408570

  •  03-07-2019
  •  | 
  •  

Вопрос

Я пытаюсь проанализировать массив объектов JSON в массив строк на С#.Я могу извлечь массив из объекта 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);

А 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;

Кто-нибудь может увидеть, что я делаю неправильно?Я полностью застрял на этом.

Это было полезно?

Решение

Сбалансированные круглые скобки — это буквально хрестоматийный пример языка, который невозможно обработать с помощью регулярных выражений.JSON, по сути, представляет собой сбалансированные круглые скобки плюс кучу других вещей, в которых фигурные скобки заменены круглыми скобками.в иерархия формальных языков, JSON — контекстно-свободный язык.Регулярные выражения не могут анализировать контекстно-свободные языки.

Некоторые системы предлагают расширения регулярных выражений, которые вроде как обрабатывают сбалансированные выражения.Однако все они уродливые хаки, все они непереносимы и в конечном итоге не подходят для этой работы.

В профессиональной работе вы почти всегда будете использовать существующий парсер JSON.Если вы хотите создать свою собственную программу в образовательных целях, я бы предложил начать с простой арифметической грамматики, поддерживающей + - * / ( ).(В JSON есть несколько правил экранирования, которые, хотя и не сложны, сделают вашу первую попытку сложнее, чем она должна быть.) По сути, вам нужно:

  1. Разложить язык на алфавит символов.
  2. Напишите контекстно-свободную грамматику в терминах тех символов, которые распознают язык.
  3. Преобразуйте грамматику в нормальную форму Хомского или достаточно близко, чтобы упростить шаг 5.
  4. Напишите лексер, который преобразует необработанный текст во входной алфавит.
  5. Напишите анализатор рекурсивного спуска, который принимает выходные данные вашего лексера, анализирует их и выдает какой-то результат.

Это типичное задание по информатике на третьем курсе практически любого университета.

Следующий шаг — выяснить, насколько сложная строка JSON вам нужна, чтобы вызвать переполнение стека в вашем рекурсивном анализаторе.Затем посмотрите на другие типы парсеров, которые можно написать, и вы поймете, почему любой, кому приходится анализировать контекстно-свободный язык в реальном мире, использует такие инструменты, как yacc или antlr, вместо того, чтобы писать парсер вручную.

Если это больше, чем вы искали, тогда вы можете смело использовать готовый парсер JSON, удовлетворенный тем, что вы узнали что-то важное и полезное:пределы регулярных выражений.

Другие советы

Сбалансированные круглые скобки — это буквально хрестоматийный пример языка, который невозможно обработать с помощью регулярных выражений.

бла-бла-бла...Проверь это:

arrayParser = "(?<Key>[\w]+)":"?(?<Value>([\s\w\d\.\\\-/:_]+(,[,\s\w\d\.\\\-/:_]+)?)+)"?

это работает для меня

если вы хотите сопоставить пустые значения, измените последний «+» на «*»

Вы используете .NET 3.5?Если да, то вы можете использовать DataContractJsonSerializer чтобы это разобрать.Нет причин делать это самостоятельно.

Если вы не используете .NET 3.5, вы можете использовать Джейрок.

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 над дверью?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top