Строка для объекта в JS

190

У меня есть строка как

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

теперь мне нужен один объект obj такой, что

obj = {firstName:name1, lastName:last1}

Как я могу сделать это в JS?

Рахул
источник
1
Являются ли строковые значения name1 и last1 или идентификаторы, которые были определены в другом месте?
cledary
1
Требуется больше данных ... что вы делаете, если ключ или значение содержат запятую или двоеточие?
Брэд
Если ваша строка не отформатирована как JSON, вам, возможно, придется использовать RegEp для обработки.
bitfishxyz

Ответы:

165

На самом деле, лучшим решением является использование JSON:

Документация

JSON.parse(text[, reviver]);

Примеры:

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) Передача функции в 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();
Матей
источник
не позволю передавать функции, хотя
K2xL
2
Это правда, однако строго говоря, функции не должны быть в каких-либо объектах JSON. Для этого у вас есть RPC и т. Д., Или, если вы хотите, вы можете передать прототип функции в json и сделать это evalпозже.
Матей
36
Боюсь, не отвечает на вопрос вообще. Было бы замечательно, если бы все изменили вопрос, чтобы удовлетворить ответ. Как вы анализируете "firstName: name1, lastName: last1"? not '{"hello": "world"}'.
Ноэль Абрахамс
33
Это не отвечает на вопрос, я не знаю, почему у него так много голосов. У спрашивающего (и у меня, я гуглил и попал сюда) есть данные, которые не соответствуют стандарту JSON, поэтому не могут быть проанализированы.
Аарон Гринвальд
1
var a = "firstName: name1, lastName: last1"; JSON.parse ('{' + a + '}') выдает ошибку.
Аарон Гринвальд
73

Ваша строка выглядит как строка JSON без фигурных скобок.

Это должно работать тогда:

obj = eval('({' + str + '})');
Филипп Лейбер
источник
22
это потенциальная дыра в безопасности. Я бы не рекомендовал этот метод вообще.
Бретон
65
Это зависит от того, откуда поступают данные. Некоторые люди одержимы безопасностью. Если вы контролируете свои данные, вы можете быть более прагматичными в поиске решений. Или у вас есть взломостойкая дверь между вашей кухней и гостиной?
Филипп Лейберт
13
Это не работает. Выдает ошибку «SyntaxError: Неожиданный токен:» . Я проверил это в Chrome.
Нямбаа,
12
Решение должно заключаться в круглые скобки:obj = eval('({' + str + '})');
Кристиан
12
prc322: Все знают, что eval () не очень безопасен (и это занижение), но использование eval () является единственным правильным ответом на вопрос выше, потому что входная строка не является допустимой строкой JSON И входная строка ссылается на другие переменные по имени.
Филипп Лейберт
50

Если я правильно понимаю:

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

Я предполагаю, что имя свойства находится слева от двоеточия, а строковое значение, которое оно принимает, - справа.

Обратите внимание, что Array.forEachэто JavaScript 1.6 - вы можете использовать инструментарий для максимальной совместимости.

cdleary
источник
Привет, Cdleary ... Интересно, можешь ли ты мне помочь: stackoverflow.com/questions/9357320/… Извините, я не могу найти другой способ связаться с тобой, кроме как через комментарии к твоим ответам
Джейсон
1
Префект пост. Этот ответ очень четко использует основы JavaScript и поэтому должен работать в любом браузере
Мишель
Я нашел этот подход хорошим началом, поэтому ответ был полезным. Тем не менее, xecute имеет правильную точку, что он не вмещает строки, которые могут иметь запятые. Вы можете пойти по пути сопоставления кавычек, если ваш код должен обрабатывать строки с запятыми, но вы все равно не будете ловить случаи, когда кавычки экранированы. Просто реализуйте то, что вам нужно, затем остановитесь.
Патрик Грэм
1
В вопросе разбора текста, представленного автором вопроса, вопросы «что если» бесполезны. Мы можем принять данный пример в качестве представителя данных или просто не можем ответить, поскольку всегда может быть «что, если» прервет синтаксический анализ.
1
Афиша спрашивала о том, как разобрать необычную структуру, которая не действовала в формате JSON. @cdleary очень хорошо ответил на вопрос в данных обстоятельствах. xecute: обработка запятой в строке потребует механизма цитирования или экранирования, выходящего за рамки этого обсуждения.
Suncat2000
37

Это простой способ ...

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

вывод

name1
Wianto Wie
источник
Повышение для этого, ALTHOUGH: var string = "{firstName: 'name1', lastName: 'last1', f: function () {alert ('u has hacked ...')} ()}"; eval ('var obj' + string) Это может вас взломать ... но я думаю, что это того стоит, потому что это единственное, что работает в некоторых случаях.
Коди
12

если вы используете JQuery:

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

ПОМНИТЕ: Эвал - это зло! : D

mzalazar
источник
7
JQuery использует eval. globalEval: /** code **/ window[ "eval" ].call( window, data ); /** more code **/
SomeShinyObject
12
Строка, предоставленная владельцем вопроса, не является допустимой строкой JSON. Итак, этот код бесполезен ...
xecute
да, eval не является злом, если вы используете его в «контролируемой» среде (что угодно, кроме внешних данных, таких как файлы, сеть или пользовательский ввод, в этом случае это может быть опасно, если не «отфильтровано / проверено»).
mzalazar
11

Так как метод JSON.parse () требует, чтобы ключи объекта были заключены в кавычки, чтобы он работал правильно, нам сначала нужно преобразовать строку в строку в формате JSON перед вызовом метода 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

Это будет работать, даже если строка имеет сложный объект (как показано ниже), и все равно будет правильно преобразовываться. Просто убедитесь, что сама строка заключена в одинарные кавычки.

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

Вам нужно использовать JSON.parse () для преобразования String в Object:

var obj = JSON.parse('{ "firstName":"name1", "lastName": "last1" }');
Григор ВВТ
источник
9

Если у вас есть такая строка, foo: 1, bar: 2вы можете преобразовать ее в действительный объект с помощью:

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

Спасибо Нигглеру в #javascript за это.

Обновление с объяснениями:

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)

Запутанные документы MDN:

Демо: http://jsbin.com/hiduhijevu/edit?js,console

Функция:

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
источник
Это совершенно непонятный ответ для среднего читателя. Можете ли вы объяснить, что делает каждая строка? И каков выходной результат, учитывая входные данные ОП?
not2qubit
1
Справедливо. Обычно у меня нет времени на детализацию, и я просто добавляю полезные сведения (особенно в случае, если я столкнусь с тем же вопросом ТАК в будущем), но я понял.
corysimmons
2
Это определенно самое элегантное решение, и оно действительно отвечает на вопрос, в отличие от многих других ответов. И спасибо за объяснение!
Кэти Ха
4

Я реализовал решение в несколько строк кода, которое работает достаточно надежно.

Имея такой HTML-элемент, где я хочу передать пользовательские параметры:

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

функция анализирует пользовательские параметры и возвращает объект, чтобы использовать его где-то:

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')));
rõdu
источник
+1 за использование data-атрибута вместо создания псевдо-пользовательских атрибутов, таких как некоторые фреймворки / библиотеки.
Джон
3
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];
   });
}

Однако это не эффективно. Что происходит, когда у вас есть что-то вроде этого:

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

split()разделит «http». Поэтому я предлагаю вам использовать специальный разделитель, как труба

 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
Просто идея - вместо второго разбиения (':') вы можете разделить строку «вручную» по двоеточию FIRST с помощью indexOf («:») и рассматривать часть строки до этого двоеточия как ключ, а оставшуюся часть после двоеточия как Значение.
Ондрей Венцовский
2

Это универсальный код, независимо от того, насколько длинный ввод, но в той же схеме, если есть: separator :)

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
источник
2

Я использую JSON5 , и он работает довольно хорошо.

Хорошая часть не является она не содержит нет eval и нет new Function , очень безопасно использовать.

Джеймс Ян
источник
0

В твоем случае

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 следует избегать любой ценой.
Алекс
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);
        });

массив "objects" будет иметь все объекты

comeOnGetIt
источник
0

Я знаю, что это старый пост, но не нашел правильного ответа на вопрос.

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

Теперь вы можете использовать obj.firstNameи, obj.lastNameчтобы получить значения, которые вы обычно делаете с объектом.

Raoul
источник