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


165

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

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

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

в это:

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

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


Почему ваша строка не является 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


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…}

Мы пытаемся де -валифицировать 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.


Должно быть 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"
}


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 (откройте консоль)


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'] })");

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>


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


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\"] }"

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 + ")"));

-1

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

str = jQuery.parseJSON(str)

Вопрос задан "или jQuery" и это идеальное решение, если оно у вас есть.
Экрополис
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.