在javascript中基于AND或逻辑拆分字符串
我的问题是拆分包含逻辑操作的字符串。 例如,下面是我的示例字符串:在javascript中基于AND或逻辑拆分字符串,javascript,string,algorithm,parsing,data-structures,Javascript,String,Algorithm,Parsing,Data Structures,我的问题是拆分包含逻辑操作的字符串。 例如,下面是我的示例字符串: var rule = "device2.temperature > 20 || device2.humidity>68 && device3.temperature >10" 我需要以一种可以轻松操作逻辑的方式解析该字符串,我不确定哪种方法更好 PS:请记住,这些规则字符串可以有10个或更多不同的条件组合,如4个and和6个or。如果您绝对确定输入总是有效的话 var rule = "devi
var rule = "device2.temperature > 20 || device2.humidity>68 && device3.temperature >10"
我需要以一种可以轻松操作逻辑的方式解析该字符串,我不确定哪种方法更好
PS:请记住,这些规则字符串可以有10个或更多不同的条件组合,如4个and和6个or。如果您绝对确定输入总是有效的话
var rule = "device2.temperature > 20 || device2.humidity>68 && device3.temperature >10"
var rulePassed = eval(rule);
请记住,在大多数情况下,“eval”是“邪恶的”,可能会带来比它解决的问题更多的问题
function parse(rule){
return Function("ctx", "return("+rule.replace(/[a-z$_][a-z0-9$_\.]*/gi, "ctx.$&")+")");
}
比eval稍微好一点,因为它在sbd时最有可能抛出错误。尝试注入一些代码。
因为它将尝试在ctx对象而不是窗口对象上访问这些属性
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) );
假设没有括号,我可能会使用如下内容(JavaScript代码):
函数f(v,op,w){
var ops={
'>':函数(a,b){返回a>b;},
”,7],“| |”,[12”,Overkill:
注意,未完全测试。可能仍包含错误
而且,代码不会检查语法是否有效,只会引发一些明显的错误
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 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) )
还有什么要知道的:
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”)
fetchesdevices[2]。temperature
未实施:
解析数组和解析函数调用以及所有关于值修改的内容。这个引擎进行一些计算,它希望输入一些值,并给出一个值。不多也不少。所以,我只是从服务器接收到这个字符串,我需要创建名为device2和device3的变量,然后我将向服务器发出另一个请求,请求重新设置尝试device2和device3的实际温度值,然后最终计算该字符串。然而,我现在的问题是根据解析的字符串命名变量。因此,每当我从该字符串中捕获“device2”,我都需要执行“var device2;”你知道我该怎么做吗?你为什么要这样做?字符串从哪里来?你想要轻松操作的逻辑是什么?你需要处理括号中的分组吗?@torazaburo因为我们在物联网应用程序中使用第三方后端软件ThingWorx,它们的警报功能仅限于一台设备,而我们没有合适的数据库来保存我们自己的信息。无论如何,由于某些有限的能力原因,我们必须将这些信息保存在字符串字段中,并在ThingWorx中处理数据,这就是为什么我们必须以这种方式保存这些信息。这可能很有趣,使用模板字符串:我的意思是,当你说“操作我的逻辑”时,你是说求值,还是说解析,以便进一步操作表达式?如果可以立即求值,这将完全解决我的问题,但如果不可能,那么我可以对解析的数据求值。非常感谢,我认为一旦完成数据配置,它将很好地工作。
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) )