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

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

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

Ответы [ 5 ]

38 голосов
/ 03 января 2009

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

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

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

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

Это типичное задание на третий год обучения в CS почти в любом университете.

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

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

11 голосов
/ 23 августа 2009

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

бла бла бла ... проверить это:

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

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

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

6 голосов
/ 03 января 2009

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

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

1 голос
/ 22 января 2012
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)

0 голосов
/ 03 января 2009

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

Вам нужен реальный анализатор для правильного анализа JSON.

И вообще, почему вы вообще пытаетесь разобрать JSON? Существует множество библиотек, которые могут сделать это для вас, и гораздо лучше, чем ваш код. Зачем изобретать велосипед, если за углом находится завод по производству колес с надписью FOSS над дверью?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...