2012-05-13 4 views
9

Вызов AJAX возвращает текст ответа, который включает строку JSON. Мне нужно:Извлечь JSON из текста

  1. извлечь строку JSON
  2. изменить его
  3. затем вставьте его обновить исходную строку

Я не слишком беспокоиться о выполнении шагов 2 и 3, но я могу 't выяснить, как сделать шаг 1. Я думал об использовании регулярного выражения, но я не знаю, как мой JSON может иметь несколько уровней с вложенными объектами или массивами.

+2

Вы здесь не новичок. Что вы пробовали? Как выглядит ваш ответ? –

+0

Кроме того, RegEx, вероятно, не является правильным инструментом для работы. –

+0

@Truth Моим единственным обходным решением до сих пор является включение маркеров в текст ответа, чтобы показать начало и конец строки JSON. Ничто не может гордиться, или это будет направлять ответ. – Christophe

ответ

9

Вы не можете использовать регулярное выражение для извлечения JSON из произвольного текста. Так как регулярные выражения обычно not powerful enough to validate JSON (если вы не можете использовать PCRE), они также не могут сравниться с ним - если бы они могли, они могли бы также проверить JSON.

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

  • Найти первое отверстие ({ или [) и последний закрытие (} или ]) скобка в вашей строке.
  • Попробуйте разобрать этот текст (включая фигурные скобки) с помощью JSON.parse(). Если это удалось, закончить и вернуть результат анализа.
  • Возьмите предыдущую закрывающую фигуру и попробуйте разобрать эту строку. Если это удастся, вы закончите снова.
  • Повторяйте это до тех пор, пока не получите скобу или ту, которая находится перед текущей открытой скобой.
  • Найдите первую открывающую скобку после первой с шага 1. Если вы ее не нашли, строка не содержит объект/массив JSON, и вы можете остановиться.
  • Перейти к шагу 2.

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

function extractJSON(str) { 
    var firstOpen, firstClose, candidate; 
    firstOpen = str.indexOf('{', firstOpen + 1); 
    do { 
     firstClose = str.lastIndexOf('}'); 
     console.log('firstOpen: ' + firstOpen, 'firstClose: ' + firstClose); 
     if(firstClose <= firstOpen) { 
      return null; 
     } 
     do { 
      candidate = str.substring(firstOpen, firstClose + 1); 
      console.log('candidate: ' + candidate); 
      try { 
       var res = JSON.parse(candidate); 
       console.log('...found'); 
       return [res, firstOpen, firstClose + 1]; 
      } 
      catch(e) { 
       console.log('...failed'); 
      } 
      firstClose = str.substr(0, firstClose).lastIndexOf('}'); 
     } while(firstClose > firstOpen); 
     firstOpen = str.indexOf('{', firstOpen + 1); 
    } while(firstOpen != -1); 
} 

var obj = {'foo': 'bar', xxx: '} me[ow]'}; 
var str = 'blah blah { not {json but here is json: ' + JSON.stringify(obj) + ' and here we have stuff that is } really } not ] json }} at all'; 
var result = extractJSON(str); 
console.log('extracted object:', result[0]); 
console.log('expected object :', obj); 
console.log('did it work  ?', JSON.stringify(result[0]) == JSON.stringify(obj) ? 'yes!' : 'no'); 
console.log('surrounding str :', str.substr(0, result[1]) + '<JSON>' + str.substr(result[2])); 

Demo (выполняется в среде nodejs, но должны работать в браузере, тоже): https://paste.aeum.net/show/81/

+0

Интересно ... Ваша ссылка указывает на страницу с надписью «Да, возможна полная проверка правильности»! – Christophe

+0

О, хе-х, не прокрутил мимо принятого ответа - но хорошо, PCRE довольно мощный. Я не думаю, что эти функции доступны в JavaScript. – ThiefMaster

0

Если JSON возвращается как часть ответа ajax, почему бы не использовать разбор парсеров JSON на основе браузеров (остерегайтесь gotchas)? Или jQuery JSON Parsing?

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

Если нет, то использование RegEx станет абсолютным кошмаром. JSON, естественно, очень гибкий, и обеспечение точного анализа будет не только трудоемким, но и расточительным. Я бы, вероятно, поставил маркеры контента в начале/конце и надеюсь на лучшее. Но вы будете широко открыты для ошибок проверки и т. Д.

+0

К сожалению, я не могу его изменить. То, что я получаю в ответе, на самом деле представляет собой целый скрипт, который включает параметры в литеральном JSON. – Christophe

+0

Я в замешательстве, так как в вашем комментарии к вопросу вы добавили маркеры в начало/конец строки JSON? Как вы это сделали, не имея возможности изменить ответ? –

+0

Извините, я имею в виду, что я не могу помешать JSON смешиваться с текстом, а текст на самом деле является скриптом. – Christophe

1

Для других, кто ищет (как я был) для извлечения строк JSON из текста вообще (даже если они недействительны), вы можете принять посмотрите на этот плагин Gulp https://www.npmjs.com/package/gulp-extract-json-like.Он ищет все строки, которые, как представляется, отформатированы как строки JSON.

Создайте папку и установите пакеты.

mkdir project && cd project 
npm install gulp gulp-extract-json-like 

Создайте файл ./gulpfile.js и поместить следующее содержимое в него:

var gulp = require('gulp'); 
var extractJsonLike = require('gulp-extract-json-like'); 

gulp.task('default', function() { 
    return gulp.src('file.txt') 
    .pipe(extractJsonLike()) 
    .pipe(gulp.dest('dist')); 
}); 

Создайте файл с именем ./file.txt, который содержит текст и выполните следующую команду.

gulp 

Найдено строк JSON будет в ./dist/file.txt.

Смежные вопросы