我有一个作为事件数据流发布的数据结构:
first = 12,
second = 20,
third = 120,
fourth = false,
fifth = "Fault"
下面我有关于上述值的警报/条件,如果警报逻辑表达式的计算结果为true,则会在后端产生警报。
例如。
报警1:
(first < 10 && second > 25) || (first > 7 && second <= 22)
报警2:
fourth = true && (fifth == "Fault" || fifth == "Error")
如果我的表达式用JavaScipt语法表达,我怎么能以编程方式找到哪些变量值/组合将使逻辑表达式成为真。
例如: Alarm1:first = 9,second = 20将评估为true。 (我想找到这些值) first = 9将不足以评估为真。
那么如何找到一个或多个将使条件评估为真的变量值。
任何可以帮我解决这个问题的JavaScript解析器?
谢谢, 弧度
答案 0 :(得分:0)
这听起来像是一台简单的状态机。
状态机知道要监视的变量名称,要评估的布尔表达式以及要执行的回调。回调接收布尔表达式的结果。
当将变量赋值表达式添加到状态机时,机器会检查它正在观察的所有变量是否已累积。如果没有,机器只存储变量赋值并等待下一个赋值。否则,机器使用其累积的变量赋值来评估布尔表达式。
这个ES6代码实现了这样一个状态机。它调用eval()
,这会打开一个巨大的安全漏洞。所以请注意将JavaScript输入此代码。
function State(
_variableNames /* array */,
_booleanExpression /* string */,
_callback /* function(boolean) -> void */)
{
/* Mapping of variable names to their local assignments.
E.g. 'first' -> 'let first = 42'
See this.addVar(). */
let _variableMap = new Map();
function haveAllValuesBeenSet()
{
return _variableNames.every(name => _variableMap.has(name));
}
function getSafeAssignment(assignment)
{
/* Turn global assignments into local assignments
by prepending 'let'. This way the assigments
won't pollute the global namespace when they're
run thru eval(). */
if (assignment.startsWith('let '))
return assignment;
else if (assignment.startsWith('var '))
return 'let ' + assignment.substring(4);
else
return 'let ' + assignment;
}
function evalExpression()
{
let assigments = '';
/* IE 11 doesn't support the Map.values property. */
for (let [_, assignment] of _variableMap)
{
assigments += assignment + ';\n';
}
let expression = assigments + _booleanExpression;
/* Uncomment to see the full expression
that's being evaluated. */
console.log(expression);
try
{
return eval(expression);
}
catch (ex)
{
console.log('ERROR in evalExpression(): ' + ex.message + '\n' + expression);
}
}
/* Add a variable assigment to the state machine,
e.g. "second = 55" */
this.addVar =
function(assignment /* string */)
{
let parts = assignment.split('=').map(s => s.trim());
let name = parts[0];
let safeAssigment = getSafeAssignment(assignment);
if (!_variableNames.includes(name))
return;
if (!_variableMap.get(name))
_variableMap.set(name, safeAssigment);
if (haveAllValuesBeenSet())
{
_callback(evalExpression());
_variableMap.clear();
}
};
}
function StateAggregator()
{
let _states = [];
this.add =
function(state)
{
_states.push(state);
};
this.applyAssignment =
function(assignment)
{
for (let state of _states)
{
state.addVar(assignment);
}
};
}
/* Create two state machines. */
var firstAndSecondState = new State(
['first', 'second'],
'(first < 10 && second > 25) || (first > 7 && second <= 22)',
function(booleanResult)
{
console.log('firstAndSecondState: ' + booleanResult);
});
var fourthAndFifthState = new State(
['fourth', 'fifth'],
'fourth === true && (fifth === "Fault" || fifth === "Error")',
function(booleanResult)
{
console.log('fourthAndFifthState: ' + booleanResult);
});
/* For convenience, a simple aggregator that allows a single variable
assigment to be broadcast to all of the state machines. */
var agg = new StateAggregator();
agg.add(firstAndSecondState);
agg.add(fourthAndFifthState);
var dataStream = [
'first = 12',
'second = 20',
'third = 120',
'fourth = false',
'fifth = "Fault"'
];
for (let assignment of dataStream)
{
agg.applyAssignment(assignment);
}