#javascript
#javascript
Вопрос:
Я хочу извлечь несколько объектов json из текстовой строки, сохраняя при этом текст по обе стороны от json. Примером использования для этого является форматирование файла журнала, в котором текстовые операторы чередуются с объектами json.
Пример строки, для которой мне может потребоваться выполнить это, выглядит следующим образом…
beforetext{"Message":"The request is invalid.","ModelState":{"Id":["Unknown
contract"]}}middletext{"Message":"The request is invalid.","ModelState":
{"Id":["Unknown contract"]}}aftertext
Я добился некоторого прогресса, выполнив поиск { и }, и с помощью индексов я смог извлечь и разрезать строку, пока не получил свои объекты json и другой текст.
Проблема в том, что объект json может содержать несколько символов { и }, как в примере выше, и я не могу точно определить, где один объект окончательно начинается и заканчивается.
Как только я извлеку json и текст между ними, я буду выглядеть так..
beforetext
{
"Message": "The request is invalid.",
"ModelState": {
"Id": [
"Unknown contract"
]
}
}
middletext
{
"Message": "The request is invalid.",
"ModelState": {
"Id": [
"Unknown contract"
]
}
}
aftertext
Я изучил регулярное выражение, но не смог найти четкого решения.
Есть идеи?
Комментарии:
1. Если вы можете быть уверены, что before / middle / after-text не содержит никаких
{}
символов и не содержит никаких строковых значений json, вы можете вести подсчет вашей «глубины» в объекте json — каждый раз, когда вы сталкиваетесь с{
, увеличивайте свой счетчик, каждый раз, когда вы сталкиваетесь с}
, уменьшайтеваш счетчик. Когда ваш счетчик достигает 0, вы получаете полный объект JSON. Если вы считаете, что ваш текст может содержать эти символы, вам нужно пройтись по строке, отслеживая, в каком состоянии в данный момент находится курсор. (См sites.google.com/site/gson/streaming )2. Спасибо @AndrewRueckert. Я смог реализовать решение (добавленное ниже), основанное на этой идее, которое соответствует моим потребностям.
Ответ №1:
Это не так уж сложно разобрать самостоятельно, если вы можете разумно предсказать, с какой строкой вы будете иметь дело. Вы можете сохранить стек своих разделителей, и когда стек достигает или отклоняется от нулевой длины, вы знаете, что находитесь на границе. Вы можете использовать строки как целые единицы, чтобы они могли содержать что угодно (кроме "
).
Это предполагает, что строки и контейнеры сбалансированы, но нетрудно добавить базовую проверку ошибок в этот синтаксический анализатор. Я изменил ваши данные, чтобы добавить еще несколько трудностей (например, начиная с [
и включая {}
в строки)
let s = 'beforetext[{"Message":"The request is {invalid.}"},{"ModelState":{"Id":["Unknown contract"]}}]middletext{"Message":"The request is invalid.","ModelState": {"Id":["Unknown contract"]}}aftertext'
function balance(s){
let opens = ['{', '['], closes = ['}', ']'], // define opening and closing delimiters
res = [], current = '', stack = []
for (let i = 0; i<s.length; i ){
let char = s[i]
if (char == '"'){ // take strings as units to allow them to contain delimters
let next = s.indexOf('"', i 1)
current = s.substring(i, next 1)
i = next
}
else if(opens.includes(char)) { // new opening, push to stack
if (stack.length == 0){
res.push(current)
current = char
}
stack.push(char)
} else if (closes.includes(char)) { // new closing pop
stack.pop()
if (stack.length == 0) {
res.push(current char)
current = ''
}
}
else {current = char}
}
res.push(current)
return res
}
console.log(balance(s).join('nn'))
Ответ №2:
Мне удалось решить эту проблему, реализовав предложение Эндрю Рюкерта
- Я перебрал каждый символ в строке.
- Если я столкнулся с ‘{‘, я увеличил глубину на 1. Если это ‘}’, я уменьшил глубину на 1.
- Всякий раз, когда глубина была равна 0, я знал, что это мои начальный и конечный индексы для json.
- Я сохранил текст до начального индекса и json как объект. Затем я перенес эти свойства в массив.
- Некоторая дополнительная логика для учета конца строки, где остается текст, но нет json, и если строка не содержит никаких ‘{‘ или ‘}’.
Пример…
jsonObjects()
{
var jsonString = this.value;
var jsonObjects = [];
var remainingString = '';
var depth = 0;
var indexStart = 0;
var indexEnd = 0;
var pointer = 0;
if (!jsonString.includes('{') amp;amp; !jsonString.includes('}')) {
jsonObjects.push({ "pretext": jsonString, "json": null });
}
else {
for (var i = 0; i < jsonString.length; i )
{
if (jsonString.charAt(i) === '{') {
if (depth === 0) {
indexStart = i;
}
depth ;
}
else if (jsonString.charAt(i) === '}') {
depth--;
if (depth === 0) {
indexEnd = i;
var finalJson = JSON.parse(jsonString.substring(indexStart, indexEnd 1));
var gapText = jsonString.substring(pointer, indexStart);
jsonObjects.push({ "pretext": gapText, "json": finalJson });
pointer = indexEnd 1;
remainingString = jsonString.substring(pointer, jsonString.length);
if (!remainingString.includes('{') amp;amp; !remainingString.includes('}')) {
jsonObjects.push({ "pretext": remainingString, "json": null });
}
}
}
}
}
return jsonObjects;
}
При некотором условном форматировании в vue результат выглядит довольно красиво..
<div v-for="jsonObject in jsonObjects" v-bind:key="jsonObject.pretext">
<p>{{ jsonObject.pretext }}</p>
<vue-json-pretty :deep="1" v-if="jsonObject.json != null" :data="jsonObject.json"></vue-json-pretty>
</div>
Ответ №3:
Я не уверен, хотите ли вы все три в качестве группы, но если нет, вы можете разделить, как показано ниже. Это даст вам массив со всеми объектами json.
let yourString = 'beforetext{"Message":"The request is invalid.","ModelState":{"Id":["Unknown contract"]}}middletext{"Message":"The request is invalid.","ModelState": {"Id":["Unknown contract"]}}aftertext'
yourString.split(/beforetextb|middletextb|aftertextb/).filter(json=>json)