Stringa da obiettare in JS


190

Ho una stringa come

string = "firstName:name1, lastName:last1"; 

ora ho bisogno di un oggetto obj tale che

obj = {firstName:name1, lastName:last1}

Come posso farlo in JS?


1
I valori o gli identificatori di stringa name1 e last1 sono stati definiti altrove?
cdleary,

1
Sono necessari ulteriori dati ... cosa stai facendo se la chiave o il valore contengono una virgola o due punti?
Brad,

Se la stringa non è formattata come JSON, potrebbe essere necessario utilizzare RegEp per il gestore.
bitfishxyz,

Risposte:


165

In realtà, la soluzione migliore sta usando JSON:

Documentazione

JSON.parse(text[, reviver]);

Esempi:

1)

var myobj = JSON.parse('{ "hello":"world" }');
alert(myobj.hello); // 'world'

2)

var myobj = JSON.parse(JSON.stringify({
    hello: "world"
});
alert(myobj.hello); // 'world'

3) Passare una funzione a JSON

var obj = {
    hello: "World",
    sayHello: (function() {
        console.log("I say Hello!");
    }).toString()
};
var myobj = JSON.parse(JSON.stringify(obj));
myobj.sayHello = new Function("return ("+myobj.sayHello+")")();
myobj.sayHello();

non consentirà il passaggio di funzioni, però
K2xL

2
Questo è vero, tuttavia le funzioni in senso stretto non dovrebbero essere presenti in nessun oggetto JSON. Per questo hai RPC ecc., O se vuoi, puoi passare il prototipo di una funzione al json e farlo in evalseguito.
Matej,

36
Temo che non risponda alla domanda. Sarebbe meraviglioso se tutti cambiassero la domanda per adattarla alla risposta. Come si analizza "firstName: name1, lastName: last1"? non "{" ciao ":" mondo "}".
Noel Abrahams,

33
Questo non risponde alla domanda, non so perché abbia così tanti voti positivi. L'interrogante (e io stesso, ho cercato su Google e sono finito qui) ha dati che non sono conformi allo standard JSON quindi non possono essere analizzati.
Aaron Greenwald,

1
var a = "firstName: name1, lastName: last1"; JSON.parse ('{' + a + '}') genera un errore.
Aaron Greenwald,

73

La tua stringa sembra una stringa JSON senza le parentesi graffe.

Questo dovrebbe funzionare quindi:

obj = eval('({' + str + '})');

22
questa è una potenziale falla nella sicurezza. Non consiglierei questo metodo.
Bretone,

65
Dipende da dove provengono i dati. Alcune persone sono ossessionate dalla sicurezza. Se controlli i tuoi dati, puoi essere più pragmatico nella ricerca di soluzioni. O hai una porta antieffrazione tra la cucina e il soggiorno?
Philippe Leybaert,

13
Questo non funziona. Ti dà l'errore "SyntaxError: token imprevisto:" . L'ho controllato in Chrome.
Nyambaa,

12
La soluzione ha bisogno di parentesi:obj = eval('({' + str + '})');
Christian

12
prc322: Tutti sanno che eval () non è molto sicuro (e questo è un eufemismo), ma l'uso di eval () è l'unica risposta corretta alla domanda sopra perché la stringa di input non è una stringa JSON valida E la stringa di input fa riferimento ad altre variabili per nome.
Philippe Leybaert,

50

Se sto capendo correttamente:

var properties = string.split(', ');
var obj = {};
properties.forEach(function(property) {
    var tup = property.split(':');
    obj[tup[0]] = tup[1];
});

Suppongo che il nome della proprietà sia a sinistra dei due punti e che il valore della stringa che assume sia a destra.

Nota che Array.forEachè JavaScript 1.6: potresti voler utilizzare un toolkit per la massima compatibilità.


Ehi, Cdleary ... mi chiedo se mi puoi aiutare: stackoverflow.com/questions/9357320/… Spiacente, non sono riuscito a trovare un altro modo per contattarti, tranne attraverso i commenti sulle tue risposte
Jason,

1
Posto perfetto. Questa risposta usa le basi di JavaScript in modo molto chiaro e dovrebbe quindi funzionare in tutti i browser
Michel,

Ho trovato questo approccio un buon inizio, quindi la risposta è stata utile. Tuttavia, xecute ha un punto valido che non accetta stringhe che possono contenere virgole. È possibile seguire il percorso delle virgolette corrispondenti se il codice deve gestire le stringhe con virgole, ma non si rileveranno comunque casi in cui le virgolette sono sfuggite. Basta implementare ciò di cui hai bisogno, quindi fermati.
Patrick Graham,

1
In una domanda di analisi del testo presentato dal richiedente, le domande su "what if" sono inutili. Possiamo accettare l'esempio dato come rappresentante dei dati o semplicemente non possiamo rispondere poiché potrebbe esserci sempre un "what if" che interromperà l'analisi.

1
Il poster ha chiesto come analizzare una struttura insolita che non era valida JSON. @cdleary ha risposto alla domanda molto bene, date le circostanze. xecute: la gestione di una virgola in una stringa richiederebbe un meccanismo di quoting o escape, oltre lo scopo di questa discussione.
Suncat2000,

37

In questo modo semplice ...

var string = "{firstName:'name1', lastName:'last1'}";
eval('var obj='+string);
alert(obj.firstName);

produzione

name1

A questo proposito, ALTHOUGH: var string = "{firstName: 'name1', lastName: 'last1', f: function () {alert ('u got hacked ...')} ()}"; eval ('var obj' + string) Questo potrebbe farti hackerare ... ma penso che ne valga la pena perché è l'unica cosa che funziona in alcuni casi.
Cody,

12

se stai usando JQuery:

var obj = jQuery.parseJSON('{"path":"/img/filename.jpg"}');
console.log(obj.path); // will print /img/filename.jpg

RICORDA: eval è malvagio! : D


7
jQuery utilizza eval. globalEval: /** code **/ window[ "eval" ].call( window, data ); /** more code **/
SomeShinyObject

12
La stringa, fornita dal proprietario della domanda, non è una stringa JSON valida. Quindi, questo codice è inutile ...
xecute

sì, eval non è male se lo si utilizza in un ambiente "controllato" (tutto tranne dati esterni come file, rete o input dell'utente, in tal caso potrebbe essere pericoloso se non "filtrato / convalidato").
mzalazar,

11

Poiché il metodo JSON.parse () richiede che le chiavi Object siano racchiuse tra virgolette perché funzioni correttamente, prima di chiamare il metodo JSON.parse () dovremmo prima convertire la stringa in una stringa formattata JSON.

var obj = '{ firstName:"John", lastName:"Doe" }';

var jsonStr = obj.replace(/(\w+:)|(\w+ :)/g, function(matchedStr) {
  return '"' + matchedStr.substring(0, matchedStr.length - 1) + '":';
});

obj = JSON.parse(jsonStr); //converts to a regular object

console.log(obj.firstName); // expected output: John
console.log(obj.lastName); // expected output: Doe

Funzionerebbe anche se la stringa avesse un oggetto complesso (come il seguente) e sarebbe comunque convertita correttamente. Assicurati solo che la stringa stessa sia racchiusa tra virgolette singole.

var strObj = '{ name:"John Doe", age:33, favorites:{ sports:["hoops", "baseball"], movies:["star wars", "taxi driver"]  }}';

var jsonStr = strObj.replace(/(\w+:)|(\w+ :)/g, function(s) {
  return '"' + s.substring(0, s.length-1) + '":';
});

var obj = JSON.parse(jsonStr);
console.log(obj.favorites.movies[0]); // expected output: star wars


10

È necessario utilizzare JSON.parse () per convertire String in un oggetto:

var obj = JSON.parse('{ "firstName":"name1", "lastName": "last1" }');

9

Se hai una stringa come questa foo: 1, bar: 2puoi convertirla in un oggetto valido con:

str
  .split(',')
  .map(x => x.split(':').map(y => y.trim()))
  .reduce((a, x) => {
    a[x[0]] = x[1];
    return a;
  }, {});

Grazie a niggler in #javascript per questo.

Aggiornamento con spiegazioni:

const obj = 'foo: 1, bar: 2'
  .split(',') // split into ['foo: 1', 'bar: 2']
  .map(keyVal => { // go over each keyVal value in that array
    return keyVal
      .split(':') // split into ['foo', '1'] and on the next loop ['bar', '2']
      .map(_ => _.trim()) // loop over each value in each array and make sure it doesn't have trailing whitespace, the _ is irrelavent because i'm too lazy to think of a good var name for this
  })
  .reduce((accumulator, currentValue) => { // reduce() takes a func and a beginning object, we're making a fresh object
    accumulator[currentValue[0]] = currentValue[1]
    // accumulator starts at the beginning obj, in our case {}, and "accumulates" values to it
    // since reduce() works like map() in the sense it iterates over an array, and it can be chained upon things like map(),
    // first time through it would say "okay accumulator, accumulate currentValue[0] (which is 'foo') = currentValue[1] (which is '1')
    // so first time reduce runs, it starts with empty object {} and assigns {foo: '1'} to it
    // second time through, it "accumulates" {bar: '2'} to it. so now we have {foo: '1', bar: '2'}
    return accumulator
  }, {}) // when there are no more things in the array to iterate over, it returns the accumulated stuff

console.log(obj)

Documenti MDN confusi:

Demo: http://jsbin.com/hiduhijevu/edit?js,console

Funzione:

const str2obj = str => {
  return str
    .split(',')
    .map(keyVal => {
      return keyVal
        .split(':')
        .map(_ => _.trim())
    })
    .reduce((accumulator, currentValue) => {
      accumulator[currentValue[0]] = currentValue[1]
      return accumulator
    }, {})
}

console.log(str2obj('foo: 1, bar: 2')) // see? works!

Questa è una risposta totalmente incomprensibile per il lettore medio. Puoi spiegare cosa fa ogni riga? E qual è l'output risultante, dato l'input dell'OP?
not2qubit

1
Giusto. In genere non ho tempo per dettagliare le cose e sto solo lasciando cadere pezzi utili (in particolare nel caso in cui mi imbatto nella stessa esatta domanda SO lungo la strada), ma ho ottenuto.
corysimmons,

2
Questa è sicuramente la soluzione più elegante e in realtà risponde alla domanda diversamente da molte altre risposte. E grazie per la spiegazione!
Cathy Ha,

4

Ho implementato una soluzione in poche righe di codice che funziona in modo abbastanza affidabile.

Avere un elemento HTML come questo in cui voglio passare opzioni personalizzate:

<div class="my-element"
    data-options="background-color: #dadada; custom-key: custom-value;">
</div>

una funzione analizza le opzioni personalizzate e restituisce un oggetto per usarlo da qualche parte:

function readCustomOptions($elem){
    var i, len, option, options, optionsObject = {};

    options = $elem.data('options');
    options = (options || '').replace(/\s/g,'').split(';');
    for (i = 0, len = options.length - 1; i < len; i++){
        option = options[i].split(':');
        optionsObject[option[0]] = option[1];
    }
    return optionsObject;
}

console.log(readCustomOptions($('.my-element')));

+1 per l'utilizzo data-dell'attributo anziché la creazione di attributi pseudo-personalizzati come alcuni framework / librerie.
Giovanni,

3
string = "firstName:name1, lastName:last1";

Questo funzionerà:

var fields = string.split(', '),
    fieldObject = {};

if( typeof fields === 'object') ){
   fields.each(function(field) {
      var c = property.split(':');
      fieldObject[c[0]] = c[1];
   });
}

Tuttavia non è efficiente. Cosa succede quando hai qualcosa del genere:

string = "firstName:name1, lastName:last1, profileUrl:http://localhost/site/profile/1";

split()dividerà "http". Quindi ti suggerisco di usare un delimitatore speciale come pipe

 string = "firstName|name1, lastName|last1";


   var fields = string.split(', '),
        fieldObject = {};

    if( typeof fields === 'object') ){
       fields.each(function(field) {
          var c = property.split('|');
          fieldObject[c[0]] = c[1];
       });
    }

2
Solo un'idea - invece della seconda divisione (':') potresti dividere la stringa "manualmente" dai PRIMI due punti usando indexOf (":") e considerare la parte della stringa fino a questi due punti come chiave e il resto dopo i due punti come il valore.
Ondrej Vencovsky,

2

Questo è un codice universale, non importa quanto il tuo input sia lungo ma nello stesso schema se c'è: separatore :)

var string = "firstName:name1, lastName:last1"; 
var pass = string.replace(',',':');
var arr = pass.split(':');
var empty = {};
arr.forEach(function(el,i){
  var b = i + 1, c = b/2, e = c.toString();
     if(e.indexOf('.') != -1 ) {
     empty[el] = arr[i+1];
  } 
}); 
  console.log(empty)

2

Sto usando JSON5 , e funziona abbastanza bene.

La parte buona è che contiene no eval e no new Function , molto sicuro da usare.


0

Nel tuo caso

var KeyVal = string.split(", ");
var obj = {};
var i;
for (i in KeyVal) {
    KeyVal[i] = KeyVal[i].split(":");
    obj[eval(KeyVal[i][0])] = eval(KeyVal[i][1]);
}

3
eval dovrebbe essere evitato a tutti i costi.
Alex

0
var stringExample = "firstName:name1, lastName:last1 | firstName:name2, lastName:last2";    

var initial_arr_objects = stringExample.split("|");
    var objects =[];
    initial_arr_objects.map((e) => {
          var string = e;
          var fields = string.split(','),fieldObject = {};
        if( typeof fields === 'object') {
           fields.forEach(function(field) {
              var c = field.split(':');
              fieldObject[c[0]] = c[1]; //use parseInt if integer wanted
           });
        }
            console.log(fieldObject)
            objects.push(fieldObject);
        });

La matrice "oggetti" avrà tutti gli oggetti


0

So che questo è un vecchio post ma non ho visto la risposta corretta alla domanda.

var jsonStrig = '{';
      var items = string.split(',');
      for (var i = 0; i < items.length; i++) {
          var current = items[i].split(':');
          jsonStrig += '"' + current[0] + '":"' + current[1] + '",';
      }
      jsonStrig = jsonStrig.substr(0, jsonStrig.length - 1);
      jsonStrig += '}';
var obj = JSON.parse(jsonStrig);
console.log(obj.firstName, obj.lastName);

Ora puoi usare obj.firstNamee obj.lastNameottenere i valori come faresti normalmente con un oggetto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.