在多维javascript对象中递归查找和替换

时间:2015-04-06 14:45:01

标签: javascript json angularjs lodash

当我的对象与正则表达式匹配时,我需要找到并替换它中的值(例如** myVar **);我需要循环的对象是用户定义的,结构各不相同。

这是一个示例对象,为简单起见缩短了。

var testObject = {
    name: "/pricing-setups/{folderId}", 
    method: "POST", 
    endpoint: "/pricing-setups/:folderId", 
    functionName: "create",
    Consumes: null,
    filename: "apicontracts/pricingsetups/PricingSetupServiceProxy.java",
    pathParam: [
        {$$hashKey: "06S",
          key: "folderId",
          value: "**myVar**"}
    ],
    queryParam: [],
    request_payload: "{'title':'EnterAname'}",
    returnList: []
}

此对象传递到主函数,该函数使用传入的对象构建angularjs资源对象。

这是我正在使用的结构:

function getTestResult(dataSource, options) {
      //input into the service should be api obj and selected environment obj

      //extend the passed object with options if passed
      var opts = $.extend({}, dataSource, options);
      //swap the {param} syntax for :param in opts.endpoint
      opts.endpoint = opts.endpoint.replace(/\}/g, "").replace(/\{/g, ":");

      //replace any defined vars passed in from scenario via scenario.userVar
      opts = replaceUserVars(opts, {"myVar": "C=1000=Corporate"});

    //MORE CODE STUFF
    // ...
    // ...
}

replaceUserVars()基于以下问题/答案,但我的情况不同,因为传入的对象(var testObject)的结构和找到的匹配的位置将发生变化。

... SO 这是我的递归解决方案,用于查找与所需正则表达式匹配的值

function replaceUserVars(api, uvars) {
      if (!uvars) {
        return api;
      }
      var pattern =  new RegExp("\\*\\*\\w*\\*\\*", "g");//match **myVar**
      //check the api params for a match to regex
      // and if we find a match, replace the string with the userVar[regex match].value

      function warpSpeedAhead(collection) {
        _.find(collection, function (obj) { //find obj in api
          if (obj !== null && typeof(obj) === "object") {
            warpSpeedAhead(obj);
          }
          else {
            if (pattern.test(obj)) { //check the regex
              var sanitVar = obj.replace(/\*/g, ""); //remove the *
              if (uvars[sanitVar]) {
                console.log("found one");
                obj = uvars[sanitVar];
                //should be equivalent to 
                //api.pathParam[0][key] = uvars[sanitVar]; //works in this case ONLY
              }
            }
          }
        });
      }
      warpSpeedAhead(api);

      return api;
    }

此函数成功找到与正则表达式匹配的值,但是,我似乎无法直接返回更新的对象而不直接重新构造testObject的结构。

这是上面代码的jsfiddle。 http://jsfiddle.net/joshvito/2Lu4oexj/

我的目标是能够搜索传入的对象,找到与正则表达式匹配的任何值,并将值更改为userVars中定义的值(如果对象值和userVar键匹配)。

5 个答案:

答案 0 :(得分:3)

如何将JSON.stringify替换为字符串并返回JSON?

JSON.parse(JSON.stringify(testObject).replace(/\*\*([^*]+)\*\*/g,function($0,$1){return uvars[$1]||$0;}))

答案 1 :(得分:2)

我根据你的问题找到了一个解决方案,一个复杂对象中的搜索和替换器......会帮助你吗?

不更改对象引用,只替换字符串...

可以看到这个小提琴中的一个例子...... http://jsfiddle.net/Castrolol/gvpnxou0/

/* definition */

function replaceVars(objSource, objReplacer){

    var pattern = replaceVars.pattern;

    if(typeof objSource === "object" ){     
        if(objSource === null) return null;

        if(objSource instanceof Array){
            for(var i = 0; i < objSource.length; i++){
             objSource[i] =  replaceVars(objSource[i], objReplacer); 
            }           
        }else{        
            for(var property in objSource){         
                objSource[property] = replaceVars(objSource[property], objReplacer);            
            }
        }

        return objSource;

    }

    if(typeof objSource === "string"){

        return objSource.replace(pattern, function(finded, varName){
            return varName in objReplacer ? objReplacer[varName] : finded;
        });

    }

    return objSource;

}


 replaceVars.pattern = /\*\*([0-9a-z_$]{1,})\*\*/gi;

您可以通过内部调用此函数来实现您的解决方案

答案 2 :(得分:1)

我修改了Luan Castros解决方案以满足我的需求。请注意,linters不鼓励使用for(key in myObject),因为它也会遍历原型属性,这可能是不需要的。与此同时,Object.keys(myObject)也可以很好地用于数组。

function recursiveSubStringReplace (source, pattern, replacement) {

    function recursiveReplace (objSource) {
        if (typeof objSource === 'string') {
            return objSource.replace(pattern, replacement);
        }

        if (typeof objSource === 'object') {
            if (objSource === null) {
                return null;
            }

            Object.keys(objSource).forEach(function (property) {
                objSource[property] = recursiveReplace(objSource[property]);
            });

            return objSource;
        }

    }

    return recursiveReplace(source);
}

答案 3 :(得分:0)

  • 首先:解决递归重命名密钥的问题。您可以使用map keys deep
  • 然后:编写您的iteratee以便返回新的密钥名称

const yourObject = { 'a': 1, 'b': 2 }; _.mapKeys(yourObject, function(value, key) { const pattern = /.*/; // whatever you want to match if (key.match(pattern)){ return key + "1234"; // return the new key name } return key; });

答案 4 :(得分:0)

对于基本数据处理,我们现在使用object-scan。它非常强大,可以使事情变得更加整洁,但是需要花费一些时间将它包裹住。这是您解决问题的方式

请注意,该函数使对象突变并返回替换计数。如果您只想替换第一个匹配项,则可以将abort设置为true

const objectScan = require('object-scan');

const replace = (p, n, data) => objectScan(['**'], {
  rtn: 'count',
  filterFn: ({ value, parent, property }) => {
    if (p.test(value)) {
      parent[property] = n;
      return true;
    }
    return false;
  }
})(data);

const testObject = {
  name: '/pricing-setups/{folderId}',
  method: 'POST',
  endpoint: '/pricing-setups/:folderId',
  functionName: 'create',
  Consumes: null,
  filename: 'apicontracts/pricingsetups/PricingSetupServiceProxy.java',
  pathParam: [{
    $$hashKey: '06S',
    key: 'folderId',
    value: '**myVar**'
  }],
  queryParam: [],
  request_payload: "{'title':'EnterAname'}",
  returnList: []
};

const r = replace(new RegExp('\\*\\*\\w*\\*\\*', 'g'), 'newValue', testObject);
console.log(r);
// => 1

console.log(JSON.stringify(testObject));
// => {"name":"/pricing-setups/{folderId}","method":"POST","endpoint":"/pricing-setups/:folderId","functionName":"create","Consumes":null,"filename":"apicontracts/pricingsetups/PricingSetupServiceProxy.java","pathParam":[{"$$hashKey":"06S","key":"folderId","value":"newValue"}],"queryParam":[],"request_payload":"{'title':'EnterAname'}","returnList":[]}