Преобразовать строку объекта в JSON

165

Как я могу преобразовать строку, которая описывает объект в строку JSON, используя JavaScript (или jQuery)?

Например: преобразовать это ( НЕ допустимая строка JSON):

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }"

в это:

str = '{ "hello": "world", "places": ["Africa", "America", "Asia", "Australia"] }'

Я хотел бы избежать использования, eval()если это возможно.

snorpey
источник
Почему ваша строка не является JSON в первую очередь? Как вы это генерируете?
Ракета Хазмат
2
Строка хранится в data-attrubute, например, так: <div data-object="{hello:'world'}"></div>я не хочу использовать одинарные кавычки в HTML (поэтому, вероятно, ей нельзя доверять)
snorpey
5
@snorpey: <div data-object='{"hello":"world"}'></div>это 100% правильный HTML (как одиночные кавычки связаны с доверием или нет?). Если вы сделаете это таким образом, вы можете просто, JSON.parseи это будет работать нормально. Примечание: ключи тоже должны быть в кавычках.
Ракета Хазмат
@Rocket спасибо за ваши усилия! Я просто хотел найти способ использовать одинарные кавычки в HTML (даже если он действителен на 100%) и в нотации JSON.
snorpey
@snorpey: они не ставят JSON в HTML-атрибут. Я думаю, что вы могли бы использовать двойные кавычки и избежать тех, которые в JSON <div data-object="{\"hello\":\"world\"}"></div>. Если вы не хотите использовать действительный JSON в атрибуте, вам придется создать свой собственный формат и проанализировать его самостоятельно.
Ракета Хазмат

Ответы:

181

Если строка из доверенного источника , вы могли бы использовать evalто JSON.stringifyрезультат. Как это:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
var json = JSON.stringify(eval("(" + str + ")"));

Обратите внимание, что когда вы eval объектный литерал, он должен быть заключен в скобки, в противном случае фигурные скобки анализируются как блок, а не как объект.

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

Мэтью Крамли
источник
это не имеет смысла, если строка из доверенного источника, почему мы конвертируем ее, вместо этого мы делаем ее действительным json.
allenhwkim
2
@allenhwkim Идея состоит в том, чтобы преобразовать недопустимый JSON в допустимый JSON, поэтому evalпреобразует строку в объект JavaScript (который работает, если строка представляет допустимый JavaScript, даже если это недопустимый JSON). Затем JSON.stringifyпреобразует из объекта обратно в (действительную) строку JSON. Вызов evalопасен, если строка не из надежного источника, потому что он может буквально запускать любой JavaScript, что открывает возможность межсайтовых скриптовых атак.
Мэтью Крамли
2
eval все равно будет делать плохие вещи в этом случае, если строка построена, например, так: var str = "(function () {console.log (\" bad \ ")}) ()";
Рондо
Использование eval () выполнит код JS. Это может быть легко злоупотреблено.
FisNaN
@allenhwkim: мы никогда не доверяем никаким источникам. Доверие к ИТ означает проверить, проверить и проверить еще раз.
Ласло Варга
110

Ваша строка не является допустимой JSON, поэтому JSON.parse(или JQuery's$.parseJSON ) не будет работать.

Один из способов - использовать evalдля «разбора» «недействительный» JSON, а затем stringify«преобразовать» его в действительный JSON.

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }"
str = JSON.stringify(eval('('+str+')'));

Я предлагаю вместо того, чтобы пытаться «исправить» ваш неверный JSON, вы начинаете с правильного JSON. Как strгенерируется, это должно быть исправлено там, до того, как будет сгенерировано, а не после.

РЕДАКТИРОВАТЬ : Вы сказали (в комментариях), эта строка хранится в атрибуте данных:

<div data-object="{hello:'world'}"></div>

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

<div data-object='{"hello":"world"}'></div>

Теперь вы можете просто использовать JSON.parse(или JQuery $.parseJSON).

var str = '{"hello":"world"}';
var obj = JSON.parse(str);
Ракета Хазмат
источник
49

jQuery.parseJSON

str = jQuery.parseJSON(str)

Редактировать. Это при условии, что у вас есть допустимая строка JSON

Farmor
источник
1
правда, я видел вопрос о том, как преобразовать строку JSON в объект
Farmor
43

Используйте простой код в ссылке ниже:

http://msdn.microsoft.com/es-es/library/ie/cc836466%28v=vs.94%29.aspx

var jsontext = '{"firstname":"Jesper","surname":"Aaberg","phone":["555-0100","555-0120"]}';
var contact = JSON.parse(jsontext);

и обратный

var str = JSON.stringify(arr);
Рональд
источник
Преобразование jsontext в объект String с помощью нового String (jsontext), вероятно, даже лучше для безопасности типов.
Нечеткий анализ
@fuzzyanalysis: нет, никогда не следует использовать примитивные обертки.
Ry-
1
JSON.parse () должен быть принятым ответом здесь, как указано @LouiseMcMahon
пиксель 67
24

Я надеюсь, что эта маленькая функция преобразует неверную строку JSON в правильную.

function JSONize(str) {
  return str
    // wrap keys without quote with valid double quote
    .replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'})    
    // replacing single quote wrapped ones to double quote 
    .replace(/'([^']+)'/g, function(_, $1){return '"'+$1+'"'})         
}

результат

var invalidJSON = "{ hello: 'world',foo:1,  bar  : '2', foo1: 1, _bar : 2, $2: 3, 'xxx': 5, \"fuz\": 4, places: ['Africa', 'America', 'Asia', 'Australia'] }"
JSON.parse(invalidJSON) 
//Result: Uncaught SyntaxError: Unexpected token h VM1058:2
JSON.parse(JSONize(invalidJSON)) 
//Result: Object {hello: "world", foo: 1, bar: "2", foo1: 1, _bar: 2…}
allenhwkim
источник
Мы пытаемся де -валифицировать b с помощью JSON.parse нашего кода, и это выглядит как хорошее решение. Нам все еще придется обрабатывать постоянные замены вручную, но, по крайней мере, это позволяет ограничить эти случаи.
Равемир
1
Это почти идеально. Не работает, когда : находится в одном из значений.
продавец
9

Используйте с осторожностью (из-за eval()):

function strToJson(str) {
  eval("var x = " + str + ";");
  return JSON.stringify(x);
}

называть как:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
alert( strToJson(str) );
Томалак
источник
3
Анонимному избирателю. Я призываю вас предоставить лучшее решение. Кроме того, причина для понижения голоса была бы хорошей.
Томалак
1
@Rocket: Вы не правы. а) eval()это единственный способ сделать это. б) Я предупредил ОП об этом. в) Посмотрите на ответ Мэтью Крамли и придумайте лучшее объяснение. (О, и г) утверждение eval()плохое - это нонсенс в этой обобщенной форме.)
Томалак
2
@Rocket: Ах, недоразумение прямо там. Извините, я думал, что голосование за вас принадлежит вам. :)
Томалак
1
@kuboslav: Работает нормально, ты вообще тестировал? Он делает eval("var x = " + str + ";")что вполне допустимо JS. Вам не нужно делать var x = ({a:12}).
Ракета Хазмат
2
@kuboslav Это не работает в IE7, потому что IE7 не имеет встроенной поддержки JSON. Он начнет работать, как только вы используете json2.js. Не будь таким счастливым.
Томалак
4

Отказ от ответственности: не пытайтесь сделать это дома, или для чего-либо, что требует, чтобы другие разработчики относились к вам серьезно:

JSON.stringify(eval('(' + str + ')'));

Там я сделал это.
Постарайся не делать этого, но Эвал для тебя ПЛОХО. Как уже говорилось выше, используйте JSON от Crockford для старых браузеров (IE7 и ниже)

Этот метод требует, чтобы ваша строка была действительным javascript , который будет преобразован в объект javascript, который затем можно сериализовать в JSON.

редактировать: исправлено, как предложено Rocket.

gonchuki
источник
Должно быть JSON.stringify(eval('('+str+')'));, не то, чтобы я потворствовал eval, но его строка не является допустимой JSON, поэтому JSON.parseне работает.
Ракета Хазмат
4

Я поставил свой ответ для тех, кто заинтересован в этой старой теме.

Я создал анализатор HTML5 data- * для плагина jQuery и демо, которые конвертируют искаженную строку JSON в объект JavaScript без использования eval().

Он может передавать атрибуты данных data5 * ниже:

<div data-object='{"hello":"world"}'></div>
<div data-object="{hello:'world'}"></div>
<div data-object="hello:world"></div>

в объект:

{
    hello: "world"
}
tokkonopapa
источник
2

У Дугласа Крокфорда есть конвертер, но я не уверен, что он поможет с плохим JSON в хороший JSON.

https://github.com/douglascrockford/JSON-js

Сет
источник
Это не очень помогает, так как строка не является допустимой JSON.
Ракета Хазмат
2

Есть намного более простой способ выполнить это умение, просто перехватите атрибут onclick фиктивного элемента, чтобы принудительно вернуть вашу строку как объект JavaScript:

var jsonify = (function(div){
  return function(json){
    div.setAttribute('onclick', 'this.__json__ = ' + json);
    div.click();
    return div.__json__;
  }
})(document.createElement('div'));

// Let's say you had a string like '{ one: 1 }' (malformed, a key without quotes)
// jsonify('{ one: 1 }') will output a good ol' JS object ;)

Вот демонстрация: http://codepen.io/csuwldcat/pen/dfzsu (откройте консоль)

csuwldcat
источник
2

Вам нужно использовать «eval», затем JSON.stringify, а затем JSON.parse для результата.

 var errorString= "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
 var jsonValidString = JSON.stringify(eval("(" + errorString+ ")"));
 var JSONObj=JSON.parse(jsonValidString);

введите описание изображения здесь

Неги Рокс
источник
1

Вы должны писать круглые скобки, потому что без них evalкод в фигурных скобках будет рассматриваться как блок команд.

var i = eval("({ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] })");
kuboslav
источник
1

Ваша лучшая и самая безопасная ставка - JSON5 - JSON for Humans . Он создан специально для этого варианта использования.

const result = JSON5.parse("{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }");

console.log(JSON.stringify(result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/json5/0.5.1/json5.min.js"></script>

Dereli
источник
1

Использование новой функции () лучше, чем eval, но все же следует использовать только с безопасным вводом.

const parseJSON = obj => Function('"use strict";return (' + obj + ')')();

console.log(parseJSON("{a:(4-1), b:function(){}, c:new Date()}"))
// outputs: Object { a: 3, b: b(), c: Date 2019-06-05T09:55:11.777Z }

Источники: MDN , 2ality

SamGoody
источник
0

В приведенном выше простом примере вы можете сделать это с помощью двух простых замен регулярных выражений:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
str.replace(/(\w+):/g, '"$1":').replace(/'/g, '"');
 => '{ "hello": "world", "places": ["Africa", "America", "Asia", "Australia"] }'

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

"{ hello: 'world', places: [\"America: The Progressive's Nightmare\"] }"
Topher Hunt
источник
0

Просто для причуд, вы можете конвертировать вашу строку через babel-standalone

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";

function toJSON() {
  return {
    visitor: {
      Identifier(path) {
        path.node.name = '"' + path.node.name + '"'
      },
      StringLiteral(path) {
        delete path.node.extra
      }
    }
  }
}
Babel.registerPlugin('toJSON', toJSON);
var parsed = Babel.transform('(' + str + ')', {
  plugins: ['toJSON']
});
var json = parsed.code.slice(1, -2)
console.log(JSON.parse(json))
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

Мориц Росслер
источник
0

var str = "{привет: 'мир', места: ['Африка', 'Америка', 'Азия', 'Австралия']}" var fStr = str .replace (/ ([Az] *) (:) / g, '"$ 1":') .replace (/ '/ g, "\" ")

console.log (JSON.parse (Fstr))введите описание изображения здесь

Извините, я на своем телефоне, вот картинка.

Фрэнсис Ли
источник
0

Решение с одним регулярным выражением и без использования eval:

str.replace(/([\s\S]*?)(')(.+?)(')([\s\S]*?)/g, "$1\"$3\"$5")

Я считаю, что это должно работать для нескольких строк и всех возможных вхождений (/ g флаг) «строки» в одинарных кавычках, заменяемых «строкой» в двойных кавычках.

Чайтанья П
источник
0
var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
var json = JSON.stringify(eval("(" + str + ")"));
praveenkumar
источник
-1

Может быть, вы должны попробовать это:

str = jQuery.parseJSON(str)
howdyhyber
источник
Вопрос задан "или jQuery" и это идеальное решение, если оно у вас есть.
Экрополис