2012-05-03 38 views
-4

我正在创建基于JSON和JavaScript的DSL,并且我要求将键值指定为'原始'并且不包含在字符串分隔符中。一个简单的例子是希望解释这一点:在解析到对象之前手动解析JSON

{myKey:custom_function('arg1'), myKey2:custom_function("another arg1")} 

应该成为

{myKey:"custom_function('arg1')", myKey2:"custom_function(\"another arg1\")"} 

这是因为在解析JSON对象时,custom_function将不存在。我需要能够解析JSON而无需评估任何值,然后只在迭代密钥时逐个扩展值。

可以使用什么正则表达式或其他方法将第一个片段转换为第二个片段?

我假设一个更简单的解决方案将覆盖90%的案例,但是编写一个防弹实施需要花费很大的精力。基于我对JavaScript的正则表达式支持的研究(显然没有lookbehind功能),我假设它需要的不仅仅是1或2行的正则表达式模式。

此外,这是一个节点应用程序,所以它的任何技巧也将有所帮助。

编辑:

这个问题似乎得到一些downvotes,但我已经离开它,无论如何,未来的Google /我自己参考的利益。这是关于什么方法/技术将工作最适合这样的问题,而且有可能很容易地面对谁的类似问题的其他节点/ JS新人一个完全有效的问题。

+0

我很抱歉,但是,什么是DSL? –

+0

域名特定语言。这是一个复杂的商业案例,用户有一项功能可以让他们编写脚本来指导应用程序。 – Trindaz

+0

我觉得downvotes是由于您的DSL是一个混合JSON样机,不使那么多的意义而不是只使用JSON作为您的DSL。与管理层的DSL应该仅仅是JSON标准争论,点即是更容易维护,面向未来的,更容易实现,啦啦啦。 – balupton

回答

0

最终回答:正则表达式不适合这样复杂的任务。我在网上找到的任何类似的复杂解决方案(例如,删除代码注释)都采用主要定制的迭代方法,只是谨慎地使用正则表达式,所以类似的方法在这种情况下不会太无痛。

所以最终的“最佳”的方法,我能找到不涉及非常多的正则表达式或任何专业图书馆从节点或其他地方适合的问题。

最后,谁可能有类似的问题未来的Google的利益,我出版了我的解决方案在https://gist.github.com/2590689及以下复制:

//clothe a hub file that has 'naked' expressions 
//e.g. turn {key:$('body p')} into {key:"$('body p')"} 
function clothe(contents){ 

closers = /[\}\]\)\/"']/ 
openers = /[\{\[\(\/"']/ 
closing = { 
    "{": "}", 
    "[": "]", 
    "(": ")", 
    "/": "/", 
    '"': '"', 
    "'": "'" 
} 

contents = contents.split(""); 

var beforeKey = true; 
var inKey = false; 
var beforeValue = false; 
var inValue = false; 
var inArray = false; 
var delimiterStack = []; 

function inDelimited(){ 
    return delimiterStack.length > 0; 
} 

function toggleDelimiter(d){ 
    if(openers.exec(d) && !closers.exec(d)){ 
     pushDelimiter(d); 
    }else if(openers.exec(d) && closers.exec(d)){ 
     if(topDelimiter()){ 
      if(topDelimiter()==d){ 
       popDelimiterIfValid(d); 
      }else{ 
       pushDelimiter(d); 
      } 
     }else{ 
      pushDelimiter(d); 
     } 
    }else if(closers.exec(d)){ 
     popDelimiterIfValid(d); 
    } 
} 

function topDelimiter(){ 
    if(delimiterStack.length>=0){ 
     return delimiterStack[delimiterStack.length-1]; 
    }else{ 
     return undefined; 
    } 
} 

function pushDelimiter(d){ 
    delimiterStack.push(d); 
} 

function popDelimiterIfValid(d){ 
    if(delimiterStack.length>0) 
     if(closing[delimiterStack[delimiterStack.length-1]]==d) 
      delimiterStack.pop(d); 
} 

function rTrimmedRightBound(rightBound){ 
    while(rightBound>0){ 
     if(!/\s/g.exec(contents[--rightBound])){ 
      return rightBound+1; 
     } 
    } 
} 

for(var i=0; i<contents.length; i++){ 

    function delimiterCheck(c){ 
     if(c=='"'){ 
      toggleDelimiter('"'); 
      contents.splice(i, 0, '\\'); 
      i++; 
     }else if(openers.exec(c) || closers.exec(c)){ 
      toggleDelimiter(c) 
     } 
    } 

    if(beforeKey){ 
     if(/[a-zA-Z0-9$_!]/.exec(contents[i])){ 
      beforeKey = false; 
      inKey = true; 
     } 
    }else if(inKey){ 
     if(contents[i]==":"){ 
      inKey = false; 
      beforeValue = true; 
     } 
    }else if(beforeValue){ 
     if(/[a-zA-Z0-9$_!'"\(\/]/.exec(contents[i])){ 
      contents.splice(i, 0, '"'); 
      i++; 
      beforeValue = false; 
      inValue = true; 
      delimiterCheck(contents[i]); 
     }else if(/\{/.exec(contents[i])){ 
      beforeKey = true; 
      beforeValue = false; 
     }else if(/\[/.exec(contents[i])){ 
      beforeValue = false; 
      inArray = true; 
     } 
    }else if(inArray && !inValue){ 
     if(/[a-zA-Z0-9$_!'"\(\/]/.exec(contents[i])){ 
      contents.splice(i, 0, '"'); 
      i++; 
      beforeValue = false; 
      inValue = true; 
      delimiterCheck(contents[i]); 
     } 
    }else if(inValue){ 
     if(!inDelimited() && /[\},\]]/.exec(contents[i])){ 
      contents.splice(rTrimmedRightBound(i), 0, '"'); 
      i++; 
      inValue = false; 
      if(/\]/.exec(contents[i])){ 
       inArray = false; 
      } 
      beforeKey = !inArray; 
     }else{ 
      delimiterCheck(contents[i]); 
     } 
    } 
} 

return contents.join(""); 
}