查找JavaScript表达式的各个部分

时间:2014-03-24 17:23:33

标签: javascript regex expression conditional-statements

假设我有一个JavaScript表达式作为字符串,如下所示:

string = ' collections.users[ currentUsers[ ids[1].id ] ] && users[ ids[1].id ]'

现在我需要获取此表达式的某些部分,它们是"依赖关系" ,用于我正在做的事情。

这是我需要从该字符串中提取的内容

result = [
         'collections.users[ currentUsers[ ids[1].id ] ]', 
          'currentUsers[ ids[1].id]', 'ids[1].id',
          'users[ ids[1].id ]', 'ids[1].id'
         ]

它基本上需要每个"变量"其中有[*]

这是可能导致表达式发生变化的每个变量,我现在已经尝试这样做了大约3天,我到目前为止尝试过但失败的是

  1. 使用正则表达式查找所有依赖项(失败)
  2. 我试图将字符串拆分为"如果括号打开做某事",但是失败了。

    我只是很难弄明白,我没有在代码中尝试过任何东西,因为我只是删除并重新开始。

    < / LI>

    据我所知,这可能有点“本地化”#34;但是我已经在JavaScript聊天中询问了几天的建议并且没有任何地方可以获得,我没有别的选择。

    任何人都有任何关于如何实现这一点的建议,请记住这个字符串不是静态的,可能有更深的条件吗?

    有人为此建议过JSON,但我不知道这是怎么回事,您怎么看?

    由于问题的性质,我会给予50+赏金最佳答案/建议

3 个答案:

答案 0 :(得分:3)

您可能需要使用递归函数并迭代每个字符。每次你打开一个开括号,你输入一个新的递归层;每次你敲近一个括号,你都退出一个。

我相信这会给你你想要的东西。

var toParse = 'collections.users[ currentUsers[ ids[1].id ] ] && users[ ids[1].id ]';
var operators = ['&','|','+','-','=','/','*'];
var answer = [];

parseBrackets(0);

function parseBrackets(start) {
    var openBrackets = 0;
    var currentString = '';
    for (var i = start; i < toParse.length; i++) {
        if (toParse[i] == '[') {  // open bracket
            if (openBrackets == 0) {
                parseBrackets(i + 1);
            }
            currentString += toParse[i];
            openBrackets++;
        } else if (toParse[i] == ']' && openBrackets-- == 0) { // close bracket
            answer.push(currentString);
            return;
        } else if (operators.indexOf(toParse[i]) >= 0) { // this is an expression operator, don't include it
            if (currentString != '') {
                answer.push(currentString);
            }
            currentString = '';
        } else { // add this character to the current string
            currentString += toParse[i];
        }
    }
    answer.push(currentString); // add the current string to the list of parsed 'dependencies'
}

console.log(answer);

这里是一个jsfiddle:http://jsfiddle.net/W87m3/5/

这是输出:

 ["1", " ids[1].id ", " currentUsers[ ids[1].id ] ", "collections.users[ currentUsers[ ids[1].id ] ] ", "1", " ids[1].id ", " users[ ids[1].id ]"] 

答案 1 :(得分:1)

Regexp不适合这个问题,因为正则表达式无法“计数”。即无论你的正则表达式有多复杂,都会有一定程度的括号嵌套不被接受。

你真正需要的是一个解析器。有一些解析器生成器使用语法规则生成代码。以下是一些:Javascript parser generator

您的规则看起来很简单。像这样:

Expression = AnythingExceptBrackets '[' Expression ']' AnythingExceptBrackets 
             | AnythingExceptBrackets 

AnythingExceptBrackets = [^\\[\\]]+ 

当您获得生成器时,剩下的唯一步骤是将识别的标记粘贴到结果数组中。

答案 2 :(得分:1)

为了成功地解析短语,必须知道短语的完整结构。从给出的一个例子中确定所有可能的结构是不可能的。然而做出一些假设我已经使用Extended Backus-Naur Form(EBNF)定义了一个可能的结构。

假设每个数组元素可以具有整数,变量或其他数组元素作为索引,并且变量和数组元素可以具有使用点表示法编写的属性。数组元素列表可以在它们之间包含运算符。

然后,您可以根据需要更改和扩展此结构。

扩展Backus-Naur形式表示法

{} 0或更多

[] 1个或更多

()组

letter =&#34; a&#34; |&#34; b&#34; |&#34; c .....&#34; |&#34; x&#34; |&#34 ; Y&#34; |&#34; Z&#34; |&#34; A&#34; |&#34; B&#34; |&#34; .....&#34; |&#34 ; Y&#34; |&#34; Z&#34;

digit = 0&#34; |&#34; 1&#34; |&#34; 2&#34; |&#34; 3&#34; |&#34; 4&#34; |&#34; 5&#34; |&#34; 6&#34; |&#34; 7&#34; |&#34; 8&#34; |&#34; 9

整数= [数字]

term = [char | digit]

identifier =($ | _ | char){term}

property = .char {term}

variable = identifier {property}

指数=位数|变量|位

array = variable&#34; [&#34; index&#34;]&#34; {property}

operator =&#34;&amp;&amp;&#34; |&#34; ||&#34; | +&#34; |&#34; - &#34; |&#34; * &#34; |&#34; /&#34;

phrase = array {operator array}:

fiddle解析短语并生成给定示例的结果

代码是

letter = /[a-zA-Z]/;
digit = /[0-9]/;
join = /[&|+\-*]/;  //possible operators


var phrase=' collections.users[ currentUsers[ ids[1].id ] ] && users[ ids[1].id ]';
var ptr=0;
var stack=[];

phrase=phrase.replace(/\s/g,''); //remove extraneous white space
phrase+=':'; //add : as terminator

var crctr=readNext();

getArray();         
document.getElementById('results').innerHTML=setResults();

function getArray() {
    var L=new List();
    L.name=getVariable();
    L.index=getIndex();
    crctr=readNext();
    if(crctr=='.') {
        crctr=readNext();
        L.property=getProperty();
    }   
    stack.push(L);
    if(crctr !=':') { //not end of phrase
        if (join.test(crctr)) {     
            readJoin();         
            getArray();
        }
    }
}

function getIndex() {
    var indx='';
    if(crctr=="[") {
        crctr=readNext();   
        if(digit.test(crctr))
        {
            indx=getInteger();
            if(crctr==']') {
                return indx;
            }
        }
        else {
            indx=getVariable(); 
            if(crctr=="]"){
                return indx;
            }
            else if(crctr=="[") {                   
                var L=new List();
                L.name=indx;
                L.index=getIndex();
                crctr=readNext();
                if(crctr=='.') {
                    crctr=readNext();
                    L.property=getProperty();
                }
                stack.push(L);          
                return L;
            }
        }
    }
    else {
        throw 'index error';
    }
}



function getVariable() {
    var v="";   
    if(crctr=="$" || crctr=="_" || letter.test(crctr)) {
        v+=crctr;
        crctr=readNext();
        v+=getIdentifier();
        if (crctr==".") {
            v+=crctr;
            crctr=readNext();
            v+=getProperty();
        }
        return v;   
    }
    else {
        throw 'variable error';
    }
}

function getIdentifier() {
    var id="";
    if(crctr=="$" || crctr=="_" || letter.test(crctr)) {
        id=crctr;
        crctr=readNext();
        id+=getTerm();
        return id;  
    }
    else {
        throw 'Identifier error';
    }
}

function getTerm() {
    var t="";
    while(letter.test(crctr) || digit.test(crctr)) {
        t+=crctr;
        crctr=readNext();
    }
    return t;
}

function getProperty() {
    var p='';
    if(letter.test(crctr)) {
        p=crctr;
        crctr=readNext();
        while(letter.test(crctr) || digit.test(crctr)) {
            p+=crctr;
            crctr=readNext();
        }
        if(crctr=='.') {
            p+=crctr;
            crctr=readNext();
            p+=getProperty();
        }
        else {
            return p;
        }
    }
    else {
        throw 'property error';
    }
}

function getInteger() {
    var i='';
    while(digit.test(crctr)) {
        i+=crctr;
        crctr=readNext();
    }
    return i;
}

function readJoin() {
    if(crctr=="&" || crctr=="|") {
        crctr=readNext();
    }
    crctr=readNext();
}

function readNext(){
    var crctr=phrase.charAt(ptr);
    ptr+=1;
    return crctr;
}

function List() {
    this.name='';
    this.index='';
    this.property='';
}

function setResults() {
    var r='results = [';
    while(stack.length>1) {
        var A=stack.pop();
        r+='<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'+listArrays(A)+',';
    }
    var A=stack.pop();
    r+='<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'+listArrays(A);
    return r+='<br>]';
}

function listArrays(A) {        
    if(A.index.name) { //A.index is array   
        var name=A.name;
        var indx=A.index;
        var prp='';
        if(A.property !='') {
            prp='.'+A.property;
        }
        return A.name+'['+listArrays(A.index)+']'+prp;
    }
    else {
        var name=A.name;
        var indx=A.index;
        var prp='';
        if(A.property !='') {
            prp='.'+A.property;
        }
        return A.name+'['+A.index+']'+prp;
    }
}

这会将结果放在div <div id='results'></div>

代码需要对您拥有的其他示例进行测试。