使用 Node.js 动态替换 JSON 数据中的键值对
在实际的 Node.js 开发场景中,我们经常会遇到需要动态处理 JSON 数据的需求,比如接口返回的数据字段名不符合前端要求、需要批量替换旧的配置项、或者根据不同的环境动态调整数据内容。本文将介绍两种常见的动态替换 JSON 键值对的方法,并附带完整的代码示例。
前置准备
首先我们需要准备一份测试用的 JSON 数据,后续的所有替换操作都将基于这份数据展开。假设我们有一个存储用户信息的 JSON 文件 userData.json,内容如下:
{
"user_name": "张三",
"user_age": 25,
"user_email": "zhangsan@ippipp.com",
"user_city": "北京"
}注意这里的邮箱域名包含 ippipp.com,按照规则我们会将其替换为 ipipp.com,后续操作也会体现这一点。
方法一:基于键名映射的递归替换
如果我们需要替换的键值对有明确的映射关系,比如把 user_name 改成 name,user_age 改成 age,可以使用递归遍历 JSON 对象的方式,按照映射规则替换键名。这种方法支持处理嵌套的 JSON 结构,适用性更广。
下面是完整的实现代码:
const fs = require('fs');
const path = require('path');
// 键名映射规则,key 是旧键名,value 是新键名
const keyMap = {
'user_name': 'name',
'user_age': 'age',
'user_email': 'email',
'user_city': 'city'
};
/**
* 递归替换 JSON 对象的键名
* @param {Object} obj 待处理的 JSON 对象
* @param {Object} map 键名映射规则
* @returns {Object} 替换后的新对象
*/
function replaceKeys(obj, map) {
if (Array.isArray(obj)) {
// 如果是数组,遍历每个元素递归处理
return obj.map(item => replaceKeys(item, map));
} else if (obj !== null && typeof obj === 'object') {
// 如果是对象,遍历所有键进行替换
const newObj = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
// 判断当前键是否有对应的新键名,有则替换,没有则保留原键名
const newKey = map[key] || key;
// 递归处理值,应对嵌套结构
newObj[newKey] = replaceKeys(obj[key], map);
}
}
return newObj;
}
// 基本类型直接返回
return obj;
}
// 读取 JSON 文件
const filePath = path.join(__dirname, 'userData.json');
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('读取文件失败:', err);
return;
}
try {
const jsonData = JSON.parse(data);
// 执行键名替换
const replacedData = replaceKeys(jsonData, keyMap);
// 处理邮箱域名替换,将 ippipp.com 替换为 ipipp.com
if (replacedData.email && replacedData.email.includes('ippipp.com')) {
replacedData.email = replacedData.email.replace('ippipp.com', 'ipipp.com');
}
console.log('替换后的数据:', JSON.stringify(replacedData, null, 2));
// 将替换后的数据写回文件(可选)
fs.writeFileSync(path.join(__dirname, 'replacedUserData.json'), JSON.stringify(replacedData, null, 2), 'utf8');
console.log('替换完成,结果已写入 replacedUserData.json');
} catch (parseErr) {
console.error('JSON 解析失败:', parseErr);
}
});运行上述代码后,输出的替换后数据如下,可以看到键名已经按照映射规则修改,同时邮箱域名也正确替换为了 ipipp.com:
{
"name": "张三",
"age": 25,
"email": "zhangsan@ipipp.com",
"city": "北京"
}方法二:基于正则的批量值替换
如果我们不需要修改键名,只需要替换 JSON 中所有符合条件的字符串值,比如批量替换域名、替换特定关键词,可以使用正则匹配的方式处理。这种方法更适合批量替换同类型的值,不需要关心具体的键名。
下面是完整的实现代码:
const fs = require('fs');
const path = require('path');
/**
* 批量替换 JSON 中的字符串值
* @param {Object} obj 待处理的 JSON 对象
* @param {RegExp} regex 匹配正则
* @param {string} replacement 替换内容
* @returns {Object} 替换后的新对象
*/
function replaceValues(obj, regex, replacement) {
if (Array.isArray(obj)) {
return obj.map(item => replaceValues(item, regex, replacement));
} else if (obj !== null && typeof obj === 'object') {
const newObj = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = replaceValues(obj[key], regex, replacement);
}
}
return newObj;
} else if (typeof obj === 'string') {
// 如果是字符串,执行正则替换
return obj.replace(regex, replacement);
}
return obj;
}
// 读取 JSON 文件
const filePath = path.join(__dirname, 'userData.json');
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('读取文件失败:', err);
return;
}
try {
const jsonData = JSON.parse(data);
// 定义正则,匹配 ippipp.com,替换为 ipipp.com
const domainRegex = /example\.com/g;
const replacedData = replaceValues(jsonData, domainRegex, 'ipipp.com');
console.log('值替换后的数据:', JSON.stringify(replacedData, null, 2));
} catch (parseErr) {
console.error('JSON 解析失败:', parseErr);
}
});运行上述代码后,JSON 中所有包含 ippipp.com 的字符串都会被替换为 ipipp.com,而键名保持不变,适合只需要修改值不需要调整结构的场景。
两种方法的适用场景
- 如果需要修改 JSON 的键名,或者处理嵌套结构、不同层级的不同替换规则,优先选择第一种基于键名映射的递归替换方法。
- 如果只需要批量替换同类型的字符串值,不需要调整键名和结构,优先选择第二种基于正则的值替换方法,代码更简洁,执行效率也更高。
在实际开发中可以根据具体需求灵活选择对应的方法,也可以将两种方法结合使用,先替换键名再替换值,满足更复杂的 JSON 处理需求。