Перетворити рядок об'єкта в 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? Як ти це генеруєш?
Ракета Hazmat

2
Рядок зберігається у data-attrubute, як це: <div data-object="{hello:'world'}"></div>і я не хочу використовувати одинарні лапки в HTML (тому, напевно, не можна довіряти)
snorpey

5
@snorpey: <div data-object='{"hello":"world"}'></div>це 100% дійсний HTML (що стосується одинарних лапок, довіряючи йому чи ні?). Якщо ви зробите це таким чином, ви можете просто JSON.parseце зробити, і це буде добре працювати. Примітка. Ключі потрібно також цитувати.
Ракета Hazmat

@Rocket дякую за ваші зусилля! Мені просто хотілося знайти спосіб використання одиничних лапок у HTML (хоча це 100% дійсне) та позначення JSON.
snorpey

@snorpey: Навпаки, це не ставити JSON в атрибут HTML на перше місце. Я думаю, ви могли б використовувати подвійні лапки і уникати тих, що знаходяться в JSON <div data-object="{\"hello\":\"world\"}"></div>. Якщо ви не хочете використовувати дійсний JSON в атрибуті, вам доведеться створити власний формат і проаналізувати його самостійно.
Ракета Hazmat

Відповіді:


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 = "(функція () {console.log (\" bad \ ")}) ()";
Рондо

Використання eval () виконає JS-код. Це можна легко зловживати.
FisNaN

@allenhwkim: ми ніколи не довіряємо жодному джерелу. Довіра до ІТ означає перевірити, перевірити та перевірити ще раз.
Ласло Варга

110

Ваша рядок недійсний JSON, тому JSON.parse(або jQuery $.parseJSON) не працюватиме.

Одним із способів було б використовувати evalдля "розбору" "недійсний" JSON, а потім stringifyйого "перетворення" на дійсний JSON.

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

Я пропоную замість того, щоб намагатися "виправити" свій недійсний JSON, ви почнете в першу чергу з дійсного JSON. Як strгенерується, його слід фіксувати там, перш ніж воно буде генеруватися, а не після.

EDIT : Ви сказали (у коментарях) цей рядок зберігається в атрибуті даних:

<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: Ні, примітивні обгортки ніколи не слід використовувати.
Ри-

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 нашого коду, і це виглядає як хороше рішення. Нам все одно доведеться обробляти постійну заміну вручну, але принаймні це дозволяє містити ці випадки.
ravemir

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}).
Ракета Hazmat

2
@kuboslav Це не працює в IE7, оскільки IE7 не має вбудованої підтримки JSON. Він почне працювати, як тільки ви користуєтесь json2.js. Не будь так щасливим.
Томалак

4

Відмова від відповідальності: не намагайтеся цього робити вдома або для того, що вимагає, щоб інші розробники сприймали вас серйозно:

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

Там я це зробив.
Постарайтеся не робити цього, eval - БАДЕ для вас. Як було сказано вище, використовуйте прошивку Crockford JSON для старих браузерів (IE7 і нижче)

Цей метод вимагає, щоб ваш рядок був дійсним javascript , який буде перетворений на об’єкт javascript, який потім може бути серіалізований у JSON.

редагувати: виправлено як запропоновано Ракета.


Це повинно бути JSON.stringify(eval('('+str+')'));не те, що я потураю eval, але його рядок недійсний JSON, тому JSON.parseне працює.
Ракета Hazmat

4

Я відповідаю за те, хто цікавиться цією старою темою.

Я створив HTML5-аналізатор даних * для модуля jQuery та демонстрації, який перетворював неправильно сформовану рядок JSON в об’єкт JavaScript без використання eval().

Він може передавати HTML5 атрибути data- * нижче:

<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 для людей . Він створений спеціально для цього випадку використання.

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

Для вашого простого прикладу, наведеного вище, ви можете зробити це, використовуючи 2 прості заміни регулярного вираження:

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

Великий застереження : Цей наївний підхід передбачає, що в об'єкта немає рядків, що містять a 'або :символ. Наприклад, я не можу придумати хороший спосіб перетворити наступний об'єкт-рядок у 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":') .замінити (/ '/ g, "\" ")

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

Вибачте, що я на телефоні, ось знімок.


0

Рішення з одним регулярним виразом та не використовуючи eval:

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

Я вважаю, що це повинно працювати для декількох рядків, а всі можливі випадки (/ g прапор) однониткового 'string' замінені на "string" з подвійною цитатами.



-1

Можливо, вам доведеться спробувати це:

str = jQuery.parseJSON(str)

Питання вказано "або jQuery", і це ідеальне рішення, якщо у вас є його.
Екрополь
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.