2016-04-13 12 views
1

私の問題は、論理演算を含む文字列を分割することです。 はたとえば、ここに私のサンプルの文字列です:JavaScriptでAND論理に基づいて文字列を分割する

var rule = "device2.temperature > 20 || device2.humidity>68 && device3.temperature >10" 

私は簡単に私のロジックを動作させることができる方法でその文字列を解析する必要があると私は良いだろうどのアプローチわかりません。

PS:これらのルール文字列には、4つのANDや6つのORなど、10種類以上の条件の組み合わせがあることにご注意ください。

+0

なぜこれをやりたいですか?文字列はどこから来たのですか?あなたは簡単に操作したいロジックは何ですか?カッコで囲まれたグループを処理する必要がありますか? –

+0

@torazaburo私たちはThingWorxと呼ばれるIOTアプリケーション用のサードパーティバックエンドソフトウェアを使用しているため、アラート機能は1つのデバイスで制限されており、独自の情報を保持できる適切なデータベースはありません。とにかく、いくつかの限られた能力の理由から、この情報を文字列フィールドに保存し、ThingWorx内のデータを処理する必要があります。そのため、このように保持する必要があります。 –

+0

これは、テンプレート文字列を使用して興味深いことがあります:http://stackoverflow.com/questions/34882100/can-you-dumb-down-es6-template-strings-to-normal-strings/34883543#34883543 –

答えて

1

あなたが入力が常に有効なJavaScript

var rule = "device2.temperature > 20 || device2.humidity>68 && device3.temperature >10" 
var rulePassed = eval(rule); 

あることを行っていることを絶対的に確信している場合は、ほとんどの場合、「evalは」「悪」であり、それよりも多くの問題を引き起こす可能性があることを覚えておいてください解決する。

+0

私はサーバからその文字列を受け取ったばかりで、device2とdevice3という変数を作成する必要があります。そして、device2とdevice3の実際の温度値を取得し、最後にその文字列を評価するためにサーバにもう一度リクエストします。 しかし、今私の問題は、解析された文字列に基づいて変数に名前を付けることです。 その文字列から "device2"を捕まえるときはいつでも、私はする必要があります "var device2;" どのように私はそれを行うことができましたか? –

1
function parse(rule){ 
    return Function("ctx", "return("+rule.replace(/[a-z$_][a-z0-9$_\.]*/gi, "ctx.$&")+")"); 
} 

evalよりも少し良くなります。なぜなら、sbdを実行するとエラーが発生する可能性が最も高いからです。いくつかのコードを注入しようとします。 これは、ウィンドウオブジェクトの代わりにctxオブジェクトのこれらのプロパティにアクセスしようとするためです。あなたが式のリストを取得するために管理することができます場合は、直列にそれらを評価することができ、

function f(v,op,w){ 
    var ops = { 
    '>': function(a,b){ return a > b; }, 
    '<': function(a,b){ return a < b; }, 
    '||': function(a,b){ return a || b; }, 
    '&&': function(a,b){ return a && b; }, 
    '==': function(a,b){ return a == b;} 
    } 

    if (ops[op]){ 
    return ops[op](v,w); 
    } else alert('Could not recognize the operator, "' + op + '".'); 
} 

を今すぐ:

var rule = parse("device2.temperature > 20 || device2.humidity>68 && device3.temperature >10"); 
var data = { 
    device2: { 
     temperature: 18, 
     humidity: 70 
    }, 

    device3: { 
     temperature: 15, 
     humidity: 75 
    } 
}; 

console.log(rule.toString()); 
console.log(rule(data)); 
1

何の括弧がないと仮定すると、私はこの(JavaScriptコード)のようなもので行くかもしれない

var exps = [[6,'>',7],'||',[12,'<',22], '&&', [5,'==',5]]; 

var i = 0, 
    result = typeof exps[i] == 'object' ? f(exps[i][0],exps[i][1],exps[i][2]) : exps[i]; 

i++; 

while (exps[i] !== undefined){ 
    var op = exps[i++], 
     b = typeof exps[i] == 'object' ? f(exps[i][0],exps[i][1],exps[i][2]) : exps[i]; 

    result = f(result,op,b); 
    i++; 
} 

console.log(result); 
1

オーバーキル:

完全にテストされていない、注意してください。まだエラーが含まれている可能性があります
そして、コードは有効な構文をチェックしませんが、いくつかの明白なエラーを投げます。

var parse = (function(){  

    function parse(){ 
     var cache = {}; 

     //this may be as evil as eval, so take care how you use it. 
     function raw(v){ return cache[v] || (cache[v] = Function("return " + v)) } 

     //parses Strings and converts them to operator-tokens or functions 
     function parseStrings(v, prop, symbol, number, string){ 
      if(!prop && !symbol && !number && !string){ 
       throw new Error("unexpected/unhandled symbol", v); 
      }else{ 
       var w; 
       switch(prop){ 
        //keywords 
        case "true": 
        case "false": 
        case "null": 
         w = raw(v); 
         break; 
       } 
       tokens.push( 
        w || 
        ~unary.indexOf(prop) && v || 
        prop && parse.fetch(v) || 
        number && raw(number) || 
        string && raw(string) || 
        symbol 
       ); 
      } 
     }  

     var tokens = []; 
     for(var i = 0; i < arguments.length; ++i){ 
      var arg = arguments[i]; 
      switch(typeof arg){ 
       case "number": 
       case "boolean": 
        tokens.push(raw(arg)); 
        break; 

       case "function": 
        tokens.push(arg); 
        break; 

       case "string": 
        //abusing str.replace() as kind of a RegEx.forEach() 
        arg.replace(matchTokens, parseStrings); 
        break; 
      } 
     } 

     for(var i = tokens.lastIndexOf("("), j; i>=0; i = tokens.lastIndexOf("(")){ 
      j = tokens.indexOf(")", i); 
      if(j > 0){ 
       tokens.splice(i, j+1-i, process(tokens.slice(i+1, j))); 
      }else{ 
       throw new Error("mismatching parantheses") 
      } 
     } 
     if(tokens.indexOf(")") >= 0) throw new Error("mismatching parantheses"); 

     return process(tokens); 
    } 

    //combines tokens and functions until a single function is left 
    function process(tokens){ 
     //unary operators like 
     unary.forEach(o => { 
      var i = -1; 
      while((i = tokens.indexOf(o, i+1)) >= 0){ 
       if((o === "+" || o === "-") && typeof tokens[i-1] === "function") continue; 
       tokens.splice(i, 2, parse[ unaryMapping[o] || o ](tokens[i+1])); 
      } 
     }) 
     //binary operators 
     binary.forEach(o => { 
      for(var i = tokens.lastIndexOf(o); i >= 0; i = tokens.lastIndexOf(o)){ 
       tokens.splice(i-1, 3, parse[ o ](tokens[i-1], tokens[i+1])); 
      } 
     }) 

     //ternary operator 
     for(var i = tokens.lastIndexOf("?"), j; i >= 0; i = tokens.lastIndexOf("?")){ 
      if(tokens[i+2] === ":"){ 
       tokens.splice(i-1, 5, parse.ternary(tokens[i-1], tokens[i+1], tokens[i+3])); 
      }else{ 
       throw new Error("unexpected symbol") 
      } 
     } 

     if(tokens.length !== 1){ 
      throw new Error("unparsed tokens left"); 
     } 
     return tokens[0]; 
    } 

    var unary = "!,~,+,-,typeof".split(","); 
    var unaryMapping = { //to avoid collisions with the binary operators 
     "+": "plus", 
     "-": "minus" 
    } 
    var binary = "**,*,/,%,+,-,<<,>>,>>>,<,<=,>,>=,==,!=,===,!==,&,^,|,&&,||".split(","); 
    var matchTokens = /([a-z$_][\.a-z0-9$_]*)|([+\-*/!~^]=*|[\(\)?:]|[<>&|=]+)|(\d+(?:\.\d*)?|\.\d+)|(["](?:\\[\s\S]|[^"])+["]|['](?:\\[\s\S]|[^'])+['])|\S/gi; 

    (function(){ 
     var def = { value: null }; 
     var odp = (k,v) => { def.value = v; Object.defineProperty(parse, k, def) }; 

     unary.forEach(o => { 
      var k = unaryMapping[o] || o; 
      k in parse || odp(k, Function("a", "return function(ctx){ return " + o + "(a(ctx)) }")); 
     }) 

     //most browsers don't support this syntax yet, so I implement this manually 
     odp("**", (a,b) => (ctx) => Math.pow(a(ctx), b(ctx))); 
     binary.forEach(o => { 
      o in parse || odp(o, Function("a,b", "return function(ctx){ return a(ctx) "+o+" b(ctx) }")); 
     }); 

     odp("ternary", (c,t,e) => ctx => c(ctx)? t(ctx): e(ctx)); 

     odp("fetch", key => { 
      var a = key.split("."); 
      return ctx => { 
       //fetches a path, like devices.2.temperature 
       //does ctx["devices"][2]["temperature"]; 
       for(var i=0, v = ctx /*|| window*/; i<a.length; ++i){ 
        if(v == null) return void 0; 
        v = v[a[i]]; 
       } 
       return v; 
      } 
     }); 

     /* some sugar */ 
     var aliases = { 
      "or": "||", 
      "and": "&&", 
      "not": "!" 
     } 
     for(var name in aliases) odp(name, parse[aliases[name]]); 
    })(); 

    return parse; 
})(); 

とあなたのコード:

var data = { 
    device2: { 
     temperature: 18, 
     humidity: 70 
    }, 

    device3: { 
     temperature: 15, 
     humidity: 75 
    } 
}; 

//you get back a function, that expects the context to work on (optional). 
//aka. (in wich context/object is `device2` defined?) 
var rule = parse("device2.temperature > 20 || device2.humidity>68 && device3.temperature >10"); 
console.log("your rule resolved:", rule(data)); 

砂糖:

コードは、演算子の優先順位を処理し、丸括弧をサポートしています。他に何を知るために

var rule1 = parse("device2.temperature > 20"); 
var rule2 = parse("device2.humidity>68 && device3.temperature >10"); 

//partials/combining rules to new ones 
//only `and` (a && b), `or` (a || b), `plus` (+value), `minus` (-value) and 'not', (!value) have named aliases 
var rule3 = parse.or(rule1, rule2); 
//but you can access all operators like this 
var rule3 = parse['||'](rule1, rule2); 
//or you can combine functions and strings 
var rule3 = parse(rule1, "||", rule2); 

console.log("(", rule1(data), "||", rule2(data), ") =", rule3(data)); 

//ternary operator and Strings (' and " supported) 
var example = parse(rule1, "? 'device2: ' + device2.temperature : 'device3: ' + device3.temperature"); 
console.log(example(data)) 

parse("devices.2.temperature")が実装されていない devices[2].temperature

をフェッチ:パスがフェッチできない場合
は、それが特定の機能は不定(ここでスローエラーなし)パスでアレイ・キーへ
アクセスを返しません

配列の解析と関数呼び出しと値変更に関するすべての解析。このエンジンはいくらかの計算を行い、いくつかの値を期待し、価値を出します。それ以上はない。

+0

ありがとうございました。データ設定が完了したらうまくいくと思います。 –

関連する問題