Регулярное выражение для анализа одного ключа: значения из JSON в Javascript

Я пытаюсь выяснить, можно ли найти отдельный keys из строки JSON в Javascript и вернуть его Value с Regex. Это похоже на создание JSON инструмента поиска.

Представьте себе следующий JSON

"{
    "Name": "Humpty",
    "Age": "18",
    "Siblings" : ["Dracula", "Snow White", "Merlin"],
    "Posts": [
        {
            "Title": "How I fell",
            "Comments": [
                { 
                    "User":"Fairy God Mother",
                    "Comment": "Ha, can't say I didn't see it coming"
                }
            ]
        }
    ]
}"

Я хочу иметь возможность выполнять поиск по строке JSON и извлекать только отдельные свойства.

давайте предположим, что это уже function, это будет выглядеть примерно так.

function getPropFromJSON(prop, JSONString){
    // Obviously this regex will only match Keys that have
    // String Values.
    var exp = new RegExp("\""+prop+"\"\:[^\,\}]*");
    return JSONString.match(exp)[0].replace("\""+prop+"\":","");    
}

Он вернет подстроку Value для Key.

e.g.

getPropFromJSON("Comments")

> "[
    { 
        "User":"Fairy God Mother",
        "Comment": "Ha, can't say I didn't see it coming"
    }
]"

Если вам интересно, почему я хочу сделать это вместо использования JSON.parse(), я создаю хранилище документов JSON вокруг localStorage. localStorage поддерживает только пары ключ/значение, поэтому я сохраняю строку JSON всего Document в уникальном файле Key. Я хочу иметь возможность выполнять запрос к документам, в идеале без накладных расходов на JSON.parsing() все Collection из Documents, а затем рекурсивно по Keys/вложенным Keys, чтобы найти совпадение.

Я не лучший в regex, поэтому я не знаю, как это сделать, и возможно ли это вообще только с regex. Это всего лишь эксперимент, чтобы выяснить, возможно ли это. Любые другие идеи в качестве решения будут оценены.


person AshHeskes    schedule 05.01.2012    source источник
comment
Это JSON, почему бы вам просто не обратиться к нему как к JSON?   -  person fge    schedule 06.01.2012
comment
@fge, если бы вы прочитали его пост, вы бы поняли, почему. Хотя на самом деле это не является веской причиной для использования регулярных выражений. Помните, что регулярное выражение - это ОБЫЧНЫЙ язык... и его не следует использовать для этого.   -  person AlanFoster    schedule 06.01.2012
comment
Сомневаюсь, что для этого стоит реализовать собственный синтаксический анализ. Это может работать лучше, если вам нужно только одно значение из огромного документа, но если вы выполняете несколько поисков, сохранение json в памяти должно быть быстрее.   -  person kapex    schedule 06.01.2012
comment
@kapep Я все равно планировал реализовать cache, но только для извлеченных Documents. Я не могу представить, что хранение всех документов в памяти будет быстрее. Мне все еще нужно iterate по Keys в каждом Document во всем Collection. Что является гораздо большим ударом по производительности, чем JSON.parse().   -  person AshHeskes    schedule 06.01.2012
comment
Нет смысла пытаться реализовать что-то подобное. Вы можете использовать конечный автомат для анализа JSON, но попытка использовать регулярное выражение никогда не даст вам полностью то, что вы хотите, потому что значения JSON могут быть массивами, объектами, строками, числами, функциями и т. д.   -  person Jonathan Rich    schedule 06.01.2012
comment
@kapep Я также планирую использовать это в мобильных приложениях, поэтому хочу свести использование памяти к минимуму.   -  person AshHeskes    schedule 06.01.2012
comment
@JonathanRich Не совсем, я могу справиться с совпавшим Value, однажды найденным, запустив его, по иронии судьбы JSON.parse(). Просто чтобы быть ясным, я не пытаюсь избежать использования JSON.parse(), внутренне он мало что делает, но все равно запускает несколько Regex. Я пытаюсь улучшить производительность в целом для варианта использования.   -  person AshHeskes    schedule 06.01.2012
comment
@JonathanRich У вас не может быть функций в JSON.   -  person Paul    schedule 06.07.2013


Ответы (2)


Я бы настоятельно отговаривал вас от этого. JSON не является обычным языком, как четко указано здесь: https://cstheory.stackexchange.com/questions/3987/is-json-a-regular-language

Цитирую пост выше:

Например, рассмотрим массив массивов массивов:

[ [ [ 1, 2], [2, 3] ] , [ [ 3, 4], [ 4, 5] ] ] 

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

Я бы рекомендовал преобразовать ваш JSON в объект (JSON.parse) и реализовать функцию поиска для обхода структуры.

Помимо этого, вы можете взглянуть на внутренности json2.js Дугласа Крокфорда. метод разбора. Возможно, измененная версия позволит вам выполнять поиск по строке JSON и просто возвращать конкретный объект, который вы искали, без преобразования всей структуры в объект. Это полезно только в том случае, если вы никогда не извлекаете какие-либо другие данные из своего JSON. Если вы это сделаете, вы могли бы также преобразовать все это для начала.

ИЗМЕНИТЬ

Чтобы еще больше показать, как работает регулярное выражение, вот регулярное выражение, которое пытается разобрать JSON.

Если вы подключите его к http://regexpal.com/ с установленным флажком "Dot Matches All". Вы обнаружите, что он может хорошо соответствовать некоторым элементам, например:

Регулярное выражение

"Comments"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\") 

JSON соответствует

"Comments": [
                { 
                    "User":"Fairy God Mother",
                    "Comment": "Ha, can't say I didn't see it coming"
                }
            ]

Регулярное выражение

"Name"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\")

JSON соответствует

"Name": "Humpty"

Однако, как только вы начнете запрашивать более высокие структуры, такие как «Сообщения», которые имеют вложенные массивы, вы обнаружите, что не можете правильно вернуть структуру, поскольку регулярное выражение не имеет контекста, в котором «]» является назначенным концом структура.

Регулярное выражение

"Posts"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\")

JSON соответствует

"Posts": [
  {
      "Title": "How I fell",
      "Comments": [
          { 
              "User":"Fairy God Mother",
              "Comment": "Ha, can't say I didn't see it coming"
          }
      ]
person Brandon Boone    schedule 06.01.2012
comment
Ранее я рассматривал метод разбора json2.js. Он действительно не делает никакого разбора. Он просто заменяет плохие/опасные/экранированные символы/контент/скрипты, чтобы JSON был чистым. Затем он просто передает чистую строку в eval();. Я думаю, ты имеешь право использовать Regex в одиночку. Я собираюсь попробовать использовать комбинацию JS и Regex. Я не согласен с преобразованием всего этого и его обходом для моего варианта использования. Это было бы слишком интенсивно для больших collections || documents, не говоря уже о поиске и сопоставлении нескольких свойств. - person AshHeskes; 06.01.2012
comment
Справедливо. Еще одна вещь, которую я мог бы порекомендовать (и я не эксперт в этой области), — это использовать формат, дружественный к реляционным данным. Я предполагаю, что Ms-Sql, MySql и Oracle имеют оптимальные способы хранения данных, поэтому чтение, запись, сравнение и объединение данных выполняются очень быстро (и я сомневаюсь, что они хранятся в формате JSON). Просто мысль. - person Brandon Boone; 06.01.2012
comment
Вы должны следовать совету в этом ответе и избегать делать это любым способом, кроме правильной десериализации JSON и поиска в полученной структуре. - person JAAulde; 06.01.2012
comment
Если вы установите конечный фиксированный предел глубины вложенности вашего JSON, он станет обычным языком, однако регулярное выражение будет очень уродливым, если только ваш предел не равен 1 или 2. - person Paul; 06.07.2013

Сначала приведите объект JSON в строку. Затем вам нужно сохранить начало и длину совпадающих подстрок. Например:

"matched".search("ch") // yields 3

Для строки JSON это работает точно так же (если вы явно не ищете запятые и фигурные скобки, и в этом случае я бы рекомендовал некоторое предварительное преобразование вашего объекта JSON перед выполнением регулярного выражения (т.е. подумайте:, {,}).

Далее вам нужно реконструировать объект JSON. Алгоритм, который я создал, делает это, определяя синтаксис JSON путем рекурсивного перехода назад от индекса совпадения. Например, псевдокод может выглядеть следующим образом:

find the next key preceding the match index, call this theKey
then find the number of all occurrences of this key preceding theKey, call this theNumber
using the number of occurrences of all keys with same name as theKey up to position of theKey, traverse the object until keys named theKey has been discovered theNumber times
return this object called parentChain

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

Вы можете увидеть библиотеку и код, который я написал, по адресу http://json.spiritway.co/.

person mikewhit    schedule 27.03.2015