【问题标题】:How to replace string with object nested values如何用对象嵌套值替换字符串
【发布时间】:2021-05-18 12:18:44
【问题描述】:

我有一个有趣的问题。 想象一下,我们有一个像这样的字符串:

'i need this {client.car.model} exactly at {client.order.time} today'

如何用对象值替换如此复杂的字段? 不知道多少级:client.car.door.left...等

当然,我可以通过循环中的正则表达式来提取它。

const re = /{(.+?)}/gi;

让正则表达式 = re.exec(s);

但在那之后 - 如何替换所有字段和子字段?

【问题讨论】:

  • 请举例说明不会被您建议的解决方案替换的字段或子字段。
  • 假设您有客户端对象,您应该构建一个小型解析器,给定一个表达式,例如{client.car.model},解析器将返回:client[car][model]。正则表达式可能不是正确的方法!
  • 我不喜欢我目前的解决方案(下一条评论)

标签: javascript string object replace


【解决方案1】:

所以,您已经正确确定了如何获取模式,所以您真正的问题是“我如何获取像 'client.order.time' 这样的字符串并为其获取值?”

使用递归函数,它非常简单。假设我们有一个像下面这样的对象:

const data = {
  client: {
    order: {
      time: '12:00PM'
    }
  }
};

我们可以创建一个函数,该函数接受一个对象和一个字符串,并递归地遍历每个部分,直到 a) 遍历所有部分并找到值或 b) 找到未知部分并返回 undefined。

const data = {
  client: {
    order: {
      time: '12:00PM'
    }
  }
};

const getValueFromPath = (obj, path, delimiter = '.') => {
  // path or obj are falsy, just return obj
  // you could tweak this bit to do something else if you want
  // obj === undefined might be from our recursive call, so keep that in mind if you tweak
  if (!path || !obj) return obj;

  const parts = path.split(delimiter);
  const next = parts.shift(); // get the first part, parts now has all the other parts
  
  // If !parts.length (parts.length === 0), we're on the last part, so we'll return.
  if (!parts.length) return obj[next];
  
  // Otherwise, recurse with the rest of the parts.
  return getValueFromPath(obj[next], parts.join(delimiter), delimiter);
};

const result = getValueFromPath(data, 'client.order.time');
console.log(result);

const noResult = getValueFromPath(data, 'path.does.not.exist');
console.log(noResult);

如果您不喜欢每次都重新join()-ing 零件,您可以使用此方法的第二个版本,它采用零件数组而不是path 字符串,但我找到了额外的代码不值得(非常少的)效率提升。

现在,回到您原来的问题,只需在字符串上使用 replace() 方法,使用替换方法作为第二个参数。该替换方法的第二个参数是模式,因此我们只需将其提供给我们的新方法。

const str = 
'i need this {client.car.model} exactly at {client.order.time} today';
const data = {
  client: {
    car: {
      model: 'Truck'
    },
    order: {
      time: '12:00PM'
    }
  }
};

const getValueFromPath = (obj, path, delimiter = '.') => {
  // path or obj are falsy, just return obj
  // you could tweak this bit to do something else if you want
  // obj === undefined might be from our recursive call, so keep that in mind if you tweak
  if (!path || !obj) return obj;

  const parts = path.split(delimiter);
  const next = parts.shift(); // get the first part, parts now has all the other parts
  
  // If !parts.length (parts.length === 0), we're on the last part, so we'll return.
  if (!parts.length) return obj[next];
  
  // Otherwise, recurse with the rest of the parts.
  return getValueFromPath(obj[next], parts.join(delimiter), delimiter);
};

const result = str.replace(/{(.+?)}/gi, (_, path) => getValueFromPath(data, path));
console.log(result);

【讨论】:

  • 那么数组呢?我们可以解析像 'client.cars[0].model' 这样的字符串吗?
  • 你可以。您只需要添加代码来检查该部分是否看起来像something[#],然后在最终返回之前进行相应的处理。
【解决方案2】:

我只是不喜欢我当前的解决方案,但它确实有效...

function objReplace(string, object) {
  const re = /{(.+?)}/gi;
  let res = string;
  let regex = re.exec(string);

  while (regex && regex[1]) {
    const ar = regex[1].split('.');
    let obj = object;
    ar.forEach((key) => {
      obj = obj[key];
    });

    obj = obj || '';
    res = res.replace(regex[0], obj);
    regex = re.exec(string);
  }
  return res.replace(/ +/g, ' ');
}

【讨论】:

    猜你喜欢
    • 2016-04-15
    • 2021-02-21
    • 2013-01-19
    • 2018-12-25
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 2014-06-30
    • 1970-01-01
    相关资源
    最近更新 更多