后端返回的字符串数据转指定的对象格式

守夜人
  • 1
新手上路,请多包涵

有大文本,格式如下,实际是以\r\n表示换行

/*
语言,项目,键值,文本
---
zh,AlarmReasonType,C2,测试预警类型
en,AlarmReasonType,C2,test alarm type
zh,AlarmReasonType,C1,忽视设备劣化
en,AlarmReasonType,C1,Ignore equipment deterioration
...
*/
const data =
  'zh,AlarmReasonType,C2,测试预警类型\r\nen,AlarmReasonType,C2,test alarm type\r\nzh,AlarmReasonType,C1,忽视设备劣化\r\nen,AlarmReasonType,C1,Ignore equipment deterioration\r\nzh,AlarmReasonType,C2,人员缺乏培训\r\nen,AlarmReasonType,C2,Lack of personnel training\r\nzh,DataType,C1,布尔\r\nen,DataType,C1,Bool\r\nzh,DataType,C2,整数\r\nen,DataType,C2,Int\r\nzh,Dictionary,code,代码\r\nen,Dictionary,code,Code\r\nzh,EquipmentType,C1,主发电机\r\nen,EquipmentType,C1,Major dynamo\r\nzh,EquipmentType,C2,中压配电板\r\nen,EquipmentType,C2,MV main switchboard\r\nzh,EquipmentType,C3,变压器\r\nen,EquipmentType,C3,Transformer\r\nzh,EquipmentUnits,C1,流送及真空\r\nen,EquipmentUnits,C1,Fllowing and Vacuum\r\nzh,EquipmentUnits,C2,电子的\r\nen,EquipmentUnits,C2,Electrical\r\nzh,EquipmentUnits,C3,浆料混合器\r\nen,EquipmentUnits,C3,Paste Mixer\r\nzh,EquipmentUnits,C4,cccc\r\nen,EquipmentUnits,C4,aaa\r\nzh,login,title,西门子船舶智能管家\r\nzh,login,logIn,登录\r\nzh,login,username,账号\r\nzh,login,password,密码\r\nen,login,title,Siemens Ship Intelligent Management System\r\nen,login,logIn,Login\r\nen,login,username,Username\r\nen,login,password,password\r\nzh,login,available,正常\r\nzh,login,unavailable,不可用\r\nzh,login,refresh,刷新\r\nen,login,available,available\r\nen,login,unavailable,unavailable\r\nen,login,refresh,refresh\r\nzh,Module,Asset,资产管理\r\nen,Module,Asset,AssetManagement\r\nzh,Permission,A00,查看资产\r\nen,Permission,A00,Show Asset\r\nen,PropertyCatalogDefine,BasicProp,BasicProp\r\nzh,PropertyCatalogDefine,BasicProp,基本信息\r\nen,PropertyCatalogDefine,DeviceParameter,DeviceParameter\r\nzh,PropertyCatalogDefine,DeviceParameter,设备参数\r\nen,PropertyCatalogDefine,DeviceStatus,DeviceStatus\r\nzh,PropertyCatalogDefine,DeviceStatus,设备状态\r\nen,PropertyCatalogDefine,DeviceDiagnose,DeviceDiagnose\r\nzh,PropertyCatalogDefine,DeviceDiagnose,设备诊断\r\nen,PropertyCatalogDefine,Additional,Additional\r\nzh,PropertyCatalogDefine,Additional,附加信息\r\nen,PropertyCatalogDefine,DeviceUnit,DeviceUnit\r\nzh,PropertyCatalogDefine,DeviceUnit,设备单元\r\nen,PropertyCatalogDefine,DeviceCircuit,DeviceCircuit\r\nzh,PropertyCatalogDefine,DeviceCircuit,设备回路\r\nen,PropertyCultureDefine,DeviceNo,DeviceNo\r\nzh,PropertyCultureDefine,DeviceNo,设备编号\r\nzh,PropertyDefine,Current,电流\r\nen,PropertyDefine,Current,Current\r\nzh,PropertyUnit,A,安培\r\nen,PropertyUnit,A,A\r\nzh,PropertyUnit,V,伏\r\nen,PropertyUnit,V,V\r\nzh,UI,save,保存\r\nen,UI,save,Save\r\nzh,UI,AddNew,新增\r\nen,UI,AddNew,New\r\n'

如何转换成下面格式的对象:

let target = {
  zh: {
    AlarmReasonType: {
      C1: '人员缺乏培训',
      C2: '测试预警类型'
    }
  },
  en: {
    AlarmReasonType: {
      C1: 'Ignore equipment deterioration',
      C2: ''
    }
  }
}
回复
阅读 482
7 个回答
const setValue = (obj, value, path) => {
  let grandpa = null
  let parent = obj
  let cur = null

  for (let i = 0; i < path.length; ++i) {
    cur = parent[path[i]]
    if (!cur) cur = parent[path[i]] = {}

    grandpa = parent
    parent = cur
  }

  grandpa[path[path.length - 1]] = value
}

const parse = (str) => {
  const paths = str.split('\r\n').map((path) => {
    const temp = path.split(',')

    const value = temp.pop()
    return [temp, value]
  })

  const ans = {}

  for (const [path, value] of paths) {
    if (!path.length) continue

    setValue(ans, value, path)
  }

  return ans
}

data.split(/\r\n/g).reduce((obj, item) => {
    if(!item)return obj
    let props = item.split(',')
    let value = props.pop(), nprop = props.pop()
    props.reduce((o, prop) => o[prop] ? o[prop] : (o[prop] = {}), obj)[nprop] = value
    return obj
}, {})
已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
function parse(str) {
    return str.split('\r\n').reduce((res, v) => {
        v.split(',').reduce((prop,k, i, arr) => {
            if(i > arr.length-2) return prop;
            prop[k] = prop[k] || {};
            return i === arr.length-2 ? prop[k] = arr[arr.length-1] : prop[k];
        }, res)
        return res;
    }, {});
}
已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入

直接上代码吧,要下班了

function demo(longString){
  const tmpArr = longString.split("\r\n").filter(Boolean) // 截断字符串并且去除空白元素
  let newObj = {} // 声明一个空对象
  // 循环插入属性
  tmpArr.forEach(item => {
    const data = item.split(",") // 属性字符串 转 属性数组
    objPushAttr(newObj, data) // 执行插入属性
  })
  return newObj
  // 对象插入属性
  function objPushAttr (obj, array) {
    const attr = array.shift() // 取出第一项作为属性键
    // 判断对象是否拥有该属性 如果没有添加该属性
    if (!obj.hasOwnProperty(attr)) obj[attr] = {}
    if (array.length < 2) {
      // 属性数组长度小于2,合并进入传入的对象
      return Object.assign(obj[attr], { [attr]: array[0] })
    } else {
      // 属性数组长度大于2,继续调用自身
      objPushAttr(obj[attr], array)
      // 返回合并后的对象
      return obj[attr]
    }
  }
}
const str = "zh,AlarmReasonType,C2,测试预警类型\r\nen,AlarmReasonType,C2...."
console.log(demo(str))
已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
const sourceArr = data.split("\r\n");
let source = {};
sourceArr.map(item => {
    if (!item) return;
    let [lan, proName, key, value] = item.split(",");
    // 已经存在的 语言
    if (source[lan]) {
        // 不存在的项目
        if (!source[lan][proName]) {
            source[lan][proName] = {};
        } 
    } else {
        source[lan] = {};
        source[lan][proName] = {};
    }
    source[lan][proName][key] = value;
});

说实在的,这个格式转换其实不太难,就是多出split切分字符串来对应操作即可完成,我想讲的时你获取的数据是否真实是你需要的数据?

从原始数据中来看,输入中C1、C2等都不是唯一的,这样就造成了它们可以是数组,也可以是后面的覆盖以前的,它们的意义不尽相同。具体的策略需要你根据实际情况选择确定。

当然,根据你当前的举例需要,规则是后面的覆盖老的。

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
data.trim().split('\n').map(v=>v.split(',')).reduce((s,n)=>{
    if(!s[n[0]]) s[n[0]] = {};
    if(!s[n[0]][n[1]]) s[n[0]][n[1]] = {};
    s[n[0]][n[1]][n[2]] = n[3]
    return s
},{})

看上去大家写的都差不多。巧了,大家都会,就你不会,我这个写的比较简陋,就是为了得出结果,看楼上还有动态适配的。

image.png

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏