【问题标题】:recursive find and replace in multidimensional javascript object多维javascript对象中的递归查找和替换
【发布时间】:2015-06-10 23:36:30
【问题描述】:

当我的对象中的值与正则表达式匹配时,我需要查找并替换它们(例如 **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)的结构和找到的匹配的位置会发生变化。

所以... 这是我找到与所需正则表达式匹配的值的递归解决方案

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 键匹配)。

【问题讨论】:

    标签: javascript json angularjs lodash


    【解决方案1】:

    JSON.stringify 和替换为字符串并返回 JSON 怎么样?

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

    【讨论】:

    • 注意:如果你有一个圆形 json 对象,这将不起作用,我建议使用 flatted import { parse, stringify} from 'flatted' 并从你的答案中删除 JSON.
    • JSON.stringify() 将删除任何值为 undefined 的属性 - 如果这对您的用例没问题,那么这个解决方案很好。
    【解决方案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;
    

    你可以通过内部调用这个函数来实现你的解决方案

    【讨论】:

    【解决方案3】:

    我根据自己的需要修改了 Luan Castro 解决方案。请注意,for(key in myObject) 不被 linter 阻止,因为它还遍历原型属性,这可能是不需要的。同时,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);
    }
    

    【讨论】:

      【解决方案4】:
      • 首先:解决递归重命名key的问题。您可以使用map keys deep
      • 然后:编写您的迭代对象,以便返回新的键名

      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; });

      【讨论】:

        【解决方案5】:

        对于基本数据处理,我们现在使用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(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: [] }
        .as-console-wrapper {max-height: 100% !important; top: 0}
        &lt;script src="https://bundle.run/object-scan@13.8.0"&gt;&lt;/script&gt;

        免责声明:我是object-scan的作者

        【讨论】:

          猜你喜欢
          • 2013-05-26
          • 2012-04-28
          • 2011-10-23
          • 2023-03-25
          • 2016-08-21
          • 1970-01-01
          • 1970-01-01
          • 2015-04-26
          • 1970-01-01
          相关资源
          最近更新 更多