Используйте regex для переименования ключей массива объектов

У меня есть массив объектов. Каждый объект имеет много ключей (более 100), и некоторые из этих ключей могут иметь специальные символы, которые я хотел бы удалить.

Я стараюсь делать то, что я хочу, таким образом:

const result = data.map(datum => {
  const keys = Object.keys(datum)
  const replacedKeys = keys.map(key => {
    const newKey = key.replace(/[.|&;$%@%"<>+]/g, '')
  })
  // ??
})

Но я уверен, что это не правильный путь..

Ответы

Ответ 1

Вы можете сопоставить новый объект с новым ключом и создать один объект с Object.assign.

const result = data.map(datum => Object.assign(...Object
    .keys(datum)
    .map(key => ({ [key.replace(/[.|&;$%@%"<>+]/g, '')]: datum[key] }))
));

Ответ 2

С методом ES8 Object.fromEntries, который уже нашел свой путь в FireFox, вы можете сделать:

const sanitiseKeys = o => Object.fromEntries(Object.entries(o).map(([k,v]) => 
                                            [k.replace(/[.|&;$%@%"<>+]/g,""), v]));

// Example use:
var data = [{ "name#": "John" }, { "@key": 2 }];

data = data.map(sanitiseKeys);

console.log(data);

Ответ 3

Вы можете преобразовать простой объект JavaScript в JSON с помощью JSON.stringify() и сопоставить свойство допустимого JSON с помощью String.prototype.replace(), а затем преобразовать обратно в простой объект JavaScript с помощью JSON.parse().

Удалено " из класса символов, поскольку допустимое свойство JSON заключено в двойные кавычки ".

RegExp

([.|&;$%@%<>+]+)(?=([^\1]+|)":)

создает группу захвата, содержащую класс символов, и соответствует классу символов, за которым следуют один или несколько символов, которых нет в классе символов, с последующей закрывающей двойной кавычкой имени свойства " последующим двоеточием или двойными кавычками с последующим двоеточием.

Соответствующий класс символов может быть заменен пустой строкой '' или любым другим символом.

let o = {"a.B|c&D;0$_%@q%<Z>5+":1};

console.log(o);

o = JSON.parse(JSON.stringify(o).replace(/([.|&;$%@%<>+]+)(?=([^\1]+|)":)/g, ''));

console.log(
  JSON.stringify(o)
, /[.|&;$%@%<>+]+/.test(Object.keys(o)[0]) // false
);

Ответ 4

Подумайте об использовании Array#reduce() для агрегирования значений для ключей вашего входного объекта. Причина этого заключается в том, что ваша санация ключа (то есть удаление нежелательных символов из ключей) может привести к тому, что отдельные пары ключ/значение вашего входного объекта "уменьшатся", так что санированная клавиша эффективно связана с несколькими значениями. Например, входной объект, такой как:

const data = {
  'key' : 'value0',
  'key&&&' : 'value1',
  'key$%<>' : 'value2'
}

будет (в зависимости от вашей гигиены) привести к выходному объекту с одним key относящимся к нескольким значениям:

const data = {
  'key' : 'value0', // what about value1, value2 ?
}

Чтобы решить эту проблему, вы можете рассмотреть возможность объединения значений с общими очищенными ключами в массив, как показано ниже:

const data = {
  'key' : 'value0',
  'key&&&' : 'value1',
  'key$%<>' : 'value2',
  'foo' : 'value3'
}

const result = Object.entries(data).reduce((obj, [ key, value ]) => {
  
  const sanitizedKey = key.replace(/[.|&;$%@%"<>+]/g, '');
  const objValue = obj[ sanitizedKey ]
  
  /* 
  Account for conflicting keys after santizing by grouping
  values in a nested array
  */
  if(objValue) {
    obj[ sanitizedKey ] = [value].concat(objValue)
  }
  else {
    obj[ sanitizedKey ] = value
  }
  
  return obj;
  
}, {});

console.log(result)

Ответ 5

Это решение основано на String.prototype.replace(), поэтому оно может принимать String или RegExp в качестве источника и допускает замену. Имейте в виду, что он не очень производительный, но использует только чистые функции:

const data = {
  someKey:   1,
  some0Key:  1,
  some1Key:  1,
  some2Key:  1,
  some3Key:  1,
  some4Key:  1,
  some5Key:  1,
  some6Key:  1,
  some7Key:  1,
  some8Key:  1,
  some9Key:  1,
  some10Key: 1,
  some11Key: 1,
  some12Key: 1,
  some13Key: 1,
  some14Key: 1,
  some15Key: 1,
};

// simple equivalent of proposed Object.fromEntries()
const fromEntries = (entries) =>
      entries.reduce((obj, [key, value]) => ({
        [key]: value,
        ...obj
      }), {});

const replaceObjectKeys = (obj, from, to) =>
      fromEntries(
        Object.entries(obj)
          .map(([key, value]) => [key.replace(from, to), value]));

console.log(replaceObjectKeys(data, /Key$/, 'prop'));