Chaîne à objet dans JS

190

J'ai une chaîne comme

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

maintenant j'ai besoin d'un objet obj tel que

obj = {firstName:name1, lastName:last1}

Comment puis-je faire cela dans JS?

rahul
la source
1
Les valeurs ou identificateurs de chaîne name1 et last1 ont-ils été définis ailleurs?
cdleary
1
Plus de données nécessaires ... que faites-vous si la clé ou la valeur contient une virgule ou un deux-points?
Brad
Si votre chaîne n'est pas au format JSON, vous devrez peut-être utiliser RegEp pour le gestionnaire.
bitfishxyz

Réponses:

165

En fait, la meilleure solution consiste à utiliser JSON:

Documentation

JSON.parse(text[, reviver]);

Exemples:

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) Passer une fonction à 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();
Matej
la source
n'autorisera pas la transmission de fonctions
K2xL
2
C'est vrai, cependant les fonctions à proprement parler ne doivent pas être dans des objets JSON. Pour cela vous avez RPC etc, ou si vous le souhaitez, vous pouvez passer le prototype d'une fonction au json, et faire evalplus tard.
Matej
36
Ne répond pas du tout à la question, j'en ai peur. Ce serait merveilleux si tout le monde changeait la question en fonction de la réponse. Comment analysez-vous "firstName: name1, lastName: last1"? pas '{"bonjour": "monde"}'.
Noel Abrahams
33
Cela ne répond pas à la question, je ne sais pas pourquoi il y a tant de votes positifs. Le questionneur (et moi-même, j'ai cherché sur Google et me suis retrouvé ici) avons des données qui ne sont pas conformes à la norme JSON et ne peuvent donc pas être analysées.
Aaron Greenwald
1
var a = "prénom: nom1, nom: dernier1"; JSON.parse ('{' + a + '}') renvoie une erreur.
Aaron Greenwald
73

Votre chaîne ressemble à une chaîne JSON sans les accolades.

Cela devrait fonctionner alors:

obj = eval('({' + str + '})');
Philippe Leybaert
la source
22
c'est une faille de sécurité potentielle. Je ne recommanderais pas du tout cette méthode.
Breton
65
Cela dépend d'où proviennent les données. Certaines personnes sont obsédées par la sécurité. Si vous contrôlez vos données, vous pouvez être plus pragmatique dans la recherche de solutions. Ou avez-vous une porte anti-effraction entre votre cuisine et votre salon?
Philippe Leybaert
13
Cela ne marche pas. Il vous donne l'erreur «SyntaxError: Unxpected token:» . Je l'ai vérifié dans Chrome.
Nyambaa
12
La solution a besoin de parenthèses autour d'elle:obj = eval('({' + str + '})');
Christian
12
prc322: Tout le monde sait que eval () n'est pas très sécurisé (et c'est un euphémisme), mais utiliser eval () est la seule réponse correcte à la question ci-dessus car la chaîne d'entrée n'est pas une chaîne JSON valide ET la chaîne d'entrée fait référence à d'autres variables de nom.
Philippe Leybaert
50

Si je comprends bien:

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

Je suppose que le nom de la propriété est à gauche du signe deux-points et que la valeur de chaîne qu'elle prend est à droite.

Notez qu'il Array.forEachs'agit de JavaScript 1.6 - vous pouvez utiliser une boîte à outils pour une compatibilité maximale.

cdleary
la source
Hey Cdleary ... je me demande si vous pouvez m'aider: stackoverflow.com/questions/9357320/... Désolé, je n'ai pas pu trouver un autre moyen de vous contacter sauf à travers des commentaires sur vos réponses
Jason
1
Poste de préfet. Cette réponse utilise les bases de JavaScript très clairement et devrait donc fonctionner dans tous les navigateurs
Michel
J'ai trouvé que cette approche était un bon début, donc la réponse était utile. Cependant, xecute a un point valide qu'il n'accepte pas les chaînes qui peuvent avoir des virgules. Vous pouvez emprunter le chemin des guillemets correspondants si votre code doit gérer des chaînes avec des virgules, mais vous n'attraperez toujours pas les cas où les guillemets sont échappés. Mettez simplement en œuvre ce dont vous avez besoin, puis arrêtez.
Patrick Graham
1
Dans une question d'analyse du texte présenté par le demandeur, les questions de «et si» sont inutiles. Nous pouvons accepter l'exemple donné comme représentatif des données ou nous ne pouvons tout simplement pas répondre car il pourrait toujours y avoir un «et si» qui briserait l'analyse.
1
L'affiche a demandé comment analyser une structure inhabituelle qui n'était pas JSON valide. @cdleary a très bien répondu à la question dans les circonstances. xecute: la gestion d'une virgule dans une chaîne nécessiterait un mécanisme de guillemet ou d'échappement, au-delà de la portée de cette discussion.
Suncat2000
37

Cette façon simple ...

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

production

name1
Wianto Wie
la source
Votez pour cela, ALTHOUGH: var string = "{firstName: 'name1', lastName: 'last1', f: function () {alert ('u got hacked ...')} ()}"; eval ('var obj' + string) Cela pourrait vous faire pirater ... mais je pense que cela en vaut la peine car c'est la seule chose qui fonctionne dans certains cas.
Cody
12

si vous utilisez JQuery:

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

N'OUBLIEZ PAS: eval est mal! :RÉ

mzalazar
la source
7
jQuery utilise eval. globalEval: /** code **/ window[ "eval" ].call( window, data ); /** more code **/
SomeShinyObject
12
La chaîne fournie par le propriétaire de la question n'est pas une chaîne JSON valide. Donc, ce code est inutile ...
xecute
oui, eval n'est pas mal si vous l'utilisez dans un environnement "contrôlé" (autre chose que des données externes comme des fichiers, un réseau ou une entrée utilisateur, dans ce cas cela pourrait être dangereux si ce n'est "filtré / validé").
mzalazar le
11

Étant donné que la méthode JSON.parse () nécessite que les clés Object soient placées entre guillemets pour qu'elle fonctionne correctement, nous devrions d'abord convertir la chaîne en une chaîne au format JSON avant d'appeler la méthode JSON.parse ().

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

Cela fonctionnerait même si la chaîne a un objet complexe (comme le suivant) et il serait toujours converti correctement. Assurez-vous simplement que la chaîne elle-même est entourée de guillemets simples.

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

Faisal Chishti
la source
10

Vous devez utiliser JSON.parse () pour convertir String en objet:

var obj = JSON.parse('{ "firstName":"name1", "lastName": "last1" }');
Grigor IWT
la source
9

Si vous avez une chaîne comme foo: 1, bar: 2vous pouvez la convertir en un objet valide avec:

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

Merci à niggler dans #javascript pour cela.

Mise à jour avec des explications:

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)

Documents MDN déroutants:

Démo: http://jsbin.com/hiduhijevu/edit?js,console

Fonction:

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!
corysimmons
la source
C'est une réponse totalement incompréhensible pour le lecteur moyen. Pouvez-vous expliquer ce que fait chaque ligne? Et quelle est la sortie résultante, étant donné l'entrée de OP?
not2qubit
1
C'est suffisant. En général, je n'ai pas le temps de détailler les choses et je ne fais que laisser tomber des éléments utiles (en particulier au cas où je rencontrerais exactement la même question SO sur la route), mais j'ai eu raison.
corysimmons
2
C'est certainement la solution la plus élégante et répond réellement à la question contrairement à beaucoup d'autres réponses. Et merci pour l'explication!
Cathy Ha
4

J'ai implémenté une solution en quelques lignes de code qui fonctionne de manière assez fiable.

Avoir un élément HTML comme celui-ci où je veux passer des options personnalisées:

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

une fonction analyse les options personnalisées et renvoie un objet pour l'utiliser quelque part:

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')));
rodu
la source
+1 pour utiliser l' data-attribut au lieu de créer des attributs pseudo-personnalisés comme certains frameworks / bibliothèques.
John
3
string = "firstName:name1, lastName:last1";

Cela fonctionnera:

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

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

Cependant, ce n'est pas efficace. Que se passe-t-il lorsque vous avez quelque chose comme ça:

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

split()divisera «http». Je vous suggère donc d'utiliser un délimiteur spécial comme un tuyau

 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];
       });
    }
Emeka Mbah
la source
2
Juste une idée - au lieu de la deuxième division (':'), vous pouvez diviser la chaîne "manuellement" par FIRST deux-points en utilisant indexOf (":") et considérer la partie de la chaîne jusqu'à ce deux-points comme clé et le reste après les deux points comme la valeur.
Ondrej Vencovsky
2

C'est du code universel, peu importe la longueur de votre entrée mais dans le même schéma s'il y a: séparateur :)

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)
panatoni
la source
2

J'utilise JSON5 et cela fonctionne plutôt bien.

La bonne partie est qu'il contient non eval et non new Function , très sûr à utiliser.

James Yang
la source
0

Dans ton cas

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]);
}
Vahag Chakhoyan
la source
3
L'évaluation doit être évitée à tout prix.
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);
        });

Le tableau "objets" aura tous les objets

comeOnGetIt
la source
0

Je sais que c'est un ancien message mais je n'ai pas vu la bonne réponse à la question.

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

Vous pouvez maintenant utiliser obj.firstNameet obj.lastNamepour obtenir les valeurs comme vous le feriez normalement avec un objet.

Raoul
la source