Konwertuj ciąg obiektu na format JSON

165

Jak przekonwertować ciąg opisujący obiekt na ciąg JSON przy użyciu JavaScript (lub jQuery)?

np .: Przekonwertuj to ( NIE jest to prawidłowy ciąg JSON):

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

zaangażowany w to:

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

Chciałbym uniknąć używania, eval()jeśli to możliwe.

snorpey
źródło
Dlaczego Twój ciąg nie jest prawidłowym kodem JSON na pierwszym miejscu? Jak to generujesz?
Rocket Hazmat
2
Ciąg jest przechowywany w data-attrubute, w ten sposób: <div data-object="{hello:'world'}"></div>i nie chcę używać pojedynczych cudzysłowów w
kodzie
5
@snorpey: <div data-object='{"hello":"world"}'></div>jest w 100% poprawnym kodem HTML (co mają wspólnego cudzysłowy z zaufaniem lub nie?). Jeśli zrobisz to w ten sposób, możesz to po prostu JSON.parsezrobić i będzie dobrze. Uwaga: klucze też muszą być cytowane.
Rocket Hazmat
@Rocket dzięki za twoje wysiłki! Chciałem tylko znaleźć sposób na obejście konieczności używania pojedynczych cudzysłowów w HTML (nawet jeśli jest to w 100% poprawne) i notacji JSON.
snorpey
@snorpey: W pierwszej kolejności nie umieszczają JSON w atrybucie HTML. Chyba mógłby użyć cudzysłowia i uciec te w JSON <div data-object="{\"hello\":\"world\"}"></div>. Jeśli nie chcesz używać prawidłowego JSON w atrybucie, będziesz musiał stworzyć własny format i samodzielnie go przeanalizować.
Rocket Hazmat

Odpowiedzi:

181

Jeśli łańcuch jest z zaufanego źródła , można użyć evalwtedy JSON.stringifywynik. Lubię to:

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

Zwróć uwagę, że kiedy jesteś evalliterałem obiektu, musi on być umieszczony w nawiasach, w przeciwnym razie nawiasy klamrowe są analizowane jako blok, a nie obiekt.

Zgadzam się również z komentarzami pod pytaniem, że znacznie lepiej byłoby po prostu zakodować obiekt w prawidłowym formacie JSON na początek i uniknąć konieczności analizowania, kodowania, a następnie prawdopodobnie ponownego analizowania . HTML obsługuje atrybuty w pojedynczych cudzysłowach (pamiętaj tylko, aby zakodować w formacie HTML wszystkie pojedyncze cudzysłowy w ciągach znaków).

Matthew Crumley
źródło
nie ma to sensu, jeśli łańcuch pochodzi z zaufanego źródła, dlaczego zamiast tego konwertujemy go, robimy go jako prawidłowy plik json.
allenhwkim
2
@allenhwkim Pomysł polega na przekonwertowaniu z nieprawidłowego JSON na poprawny JSON, więc evalkonwertuje ciąg znaków na obiekt JavaScript (który działa, o ile ciąg reprezentuje prawidłowy JavaScript, nawet jeśli nie jest to poprawny JSON). Następnie JSON.stringifykonwertuje obiekt z powrotem na (prawidłowy) ciąg JSON. Wywołanie evaljest niebezpieczne, jeśli ciąg nie pochodzi z zaufanego źródła, ponieważ może dosłownie uruchomić dowolny kod JavaScript, co otwiera możliwość ataków typu cross-site scripting.
Matthew Crumley,
2
eval nadal będzie robił złe rzeczy w tym przypadku, jeśli napis zostanie skonstruowany, na przykład w ten sposób: var str = "(function () {console.log (\" bad \ ")}) ()";
Rondo
Użycie eval () spowoduje wykonanie kodu JS. Można go łatwo nadużywać.
FisNaN
@allenhwkim: nigdy nie ufamy żadnemu źródłu. Zaufanie do IT oznacza sprawdzanie, sprawdzanie i sprawdzanie ponownie.
Laszlo Varga
110

Twój ciąg nie jest prawidłowym plikiem JSON, więc JSON.parse(lub jQuery $.parseJSON) nie będzie działać.

Jednym ze sposobów byłoby eval„przeanalizowanie” „nieprawidłowego” kodu JSON, a następnie stringify„przekonwertowanie” go na prawidłowy format JSON.

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

Sugeruję, aby zamiast próbować „naprawić” nieprawidłowy kod JSON, najpierw zacznij od prawidłowego formatu JSON. Jak jest strgenerowany, należy to naprawić tam, zanim zostanie wygenerowany, a nie po.

EDYCJA : Powiedziałeś (w komentarzach) ten ciąg jest przechowywany w atrybucie danych:

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

Proponuję naprawić to tutaj, więc może to być po prostu JSON.parsed. Po pierwsze, zarówno klucze, jak i wartości należy podać w cudzysłowach. Powinien wyglądać następująco (pojedyncze cudzysłowy atrybuty w HTML są prawidłowe):

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

Teraz możesz po prostu użyć JSON.parse(lub jQuery $.parseJSON).

var str = '{"hello":"world"}';
var obj = JSON.parse(str);
Rocket Hazmat
źródło
49

jQuery.parseJSON

str = jQuery.parseJSON(str)

Edytować. Pod warunkiem, że masz prawidłowy ciąg JSON

Farmor
źródło
1
prawda Widziałem pytanie, jak przekonwertować ciąg JSON na obiekt
Farmor
43

Użyj prostego kodu w linku poniżej:

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

i odwrotnie

var str = JSON.stringify(arr);
Ronald
źródło
Konwersja jsontext do obiektu String za pomocą new String (jsontext) jest prawdopodobnie jeszcze lepsza ze względu na bezpieczeństwo typów.
Analiza rozmyta
@fuzzyanalysis: Nie, prymitywne opakowania nigdy nie powinny być używane.
Ry-
1
JSON.parse () powinno być tutaj akceptowaną odpowiedzią, zgodnie z @LouiseMcMahon
piksel 67
24

Mam nadzieję, że ta mała funkcja konwertuje nieprawidłowy ciąg JSON na prawidłowy.

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

Wynik

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
źródło
Próbujemy zdewaluować b za pomocą JSON.parse naszego kodu i wygląda na to, że jest to dobre rozwiązanie. Nadal będziemy musieli zajmować się ciągłą wymianą ręcznie, ale przynajmniej pozwala to powstrzymać te przypadki.
ravemir
1
Jest prawie doskonały. Nie działa, gdy : jest w jednej z wartości.
seler
9

Używaj ostrożnie (ze względu na eval()):

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

zadzwoń jako:

var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
alert( strToJson(str) );
Tomalak
źródło
3
Do anonimowego przeciwnika. Wzywam Cię do zapewnienia lepszego rozwiązania. Poza tym powód do przegłosowania byłby miły.
Tomalak
1
@Rocket: Mylisz się. a) eval()to jedyny sposób, aby to zrobić. b) Ostrzegłem o tym PO. c) Spójrz na odpowiedź Matthew Crumleya i pomyśl o lepszym wyjaśnieniu. (Och, id) stwierdzenie eval()jest złe, jest nonsensem w tej uogólnionej formie.)
Tomalak
2
@Rocket: Ach, nieporozumienie. Przepraszam, myślałem, że głos przeciwny należy do Ciebie. :)
Tomalak
1
@kuboslav: Działa dobrze, czy w ogóle to przetestowałeś? Robi to, eval("var x = " + str + ";")co jest całkowicie poprawnym JS. Nie musisz tego robić var x = ({a:12}).
Rocket Hazmat
2
@kuboslav To nie działa w IE7, ponieważ IE7 nie ma natywnej obsługi formatu JSON. Zacznie działać, gdy tylko użyjesz json2.js. Nie bądź taki szczęśliwy.
Tomalak
4

Zastrzeżenie: nie próbuj tego w domu ani w przypadku niczego, co wymaga, aby inni deweloperzy traktowali Cię poważnie:

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

Tam, zrobiłem to.
Staraj się tego nie robić, eval jest dla ciebie ZŁE. Jak wspomniano powyżej, użyj podkładki JSON firmy Crockford dla starszych przeglądarek (IE7 i starszych)

Ta metoda wymaga, aby ciąg był prawidłowym skryptem javascript , który zostanie przekonwertowany na obiekt javascript, który można następnie serializować do formatu JSON.

edycja: naprawiono zgodnie z sugestią Rocket.

gonchuki
źródło
Powinno być JSON.stringify(eval('('+str+')'));, nie to, że zgadzam się eval, ale jego ciąg nie jest prawidłowym kodem JSON, więc JSON.parsenie działa.
Rocket Hazmat
4

Swoją odpowiedź umieściłem dla kogoś, kogo interesuje ten stary wątek.

Stworzyłem parser danych HTML5 * dla wtyczki i wersji demonstracyjnej jQuery, które konwertują zniekształcony ciąg JSON na obiekt JavaScript bez użycia eval().

Może przekazywać atrybuty data- * HTML5 poniżej:

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

do obiektu:

{
    hello: "world"
}
tokkonopapa
źródło
2

Jest o wiele prostszy sposób na wykonanie tego wyczynu, po prostu przejmij atrybut onclick elementu fikcyjnego, aby wymusić zwrot ciągu jako obiektu 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 ;)

Oto demo: http://codepen.io/csuwldcat/pen/dfzsu (otwórz konsolę)

csuwldcat
źródło
2

Do wyniku należy użyć „eval”, a następnie JSON.stringify i JSON.parse.

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

wprowadź opis obrazu tutaj

Negi Rox
źródło
1

Musisz pisać nawiasy okrągłe, ponieważ bez nich evalkod w nawiasach klamrowych będzie traktowany jako blok poleceń.

var i = eval("({ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] })");
kuboslav
źródło
1

Najlepszym i najbezpieczniejszym zakładem byłby JSON5 - JSON dla ludzi . Jest tworzony specjalnie dla tego przypadku użycia.

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
źródło
1

Korzystanie z nowej funkcji Function () jest lepsze niż eval, ale nadal powinno być używane tylko z bezpiecznym wprowadzaniem.

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 }

Źródła: MDN , 2ality

SamGoody
źródło
0

W powyższym prostym przykładzie możesz to zrobić za pomocą 2 prostych zamian wyrażeń regularnych:

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

Duże zastrzeżenie : to naiwne podejście zakłada, że ​​obiekt nie ma ciągów zawierających znak 'lub :. Na przykład nie mogę wymyślić dobrego sposobu na przekonwertowanie następującego ciągu obiektu na JSON bez użycia eval:

"{ hello: 'world', places: [\"America: The Progressive's Nightmare\"] }"
Topher Hunt
źródło
0

Tylko ze względu na dziwactwa możesz przekonwertować swój ciąg za pomocą 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>

Moritz Roessler
źródło
0

var str = "{hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia']}" var fStr = str .replace (/ ([Az] *) (:) / g, '"$ 1":') .replace (/ '/ g, "\" ")

console.log (JSON.parse (fStr))wprowadź opis obrazu tutaj

Przepraszam, rozmawiam przez telefon, oto zdjęcie.

Francis Leigh
źródło
0

Rozwiązanie z jednym wyrażeniem regularnym i nie używające eval:

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

Uważam, że powinno to działać dla wielu wierszy i wszystkich możliwych wystąpień (flaga / g) pojedynczego cudzysłowu „ciągu” zastąpionego podwójnym cudzysłowem „ciąg”.

Chaitanya P
źródło
0
var str = "{ hello: 'world', places: ['Africa', 'America', 'Asia', 'Australia'] }";
var json = JSON.stringify(eval("(" + str + ")"));
praveenkumar
źródło
-1

Może musisz spróbować tego:

str = jQuery.parseJSON(str)
Howdyhyber
źródło
Pytanie zostało określone jako „lub jQuery” i jest to idealne rozwiązanie, jeśli masz je dostępne.
Ecropolis