基于空间存储性能和高效的考虑,我新设计了一种的新的逻辑前缀表达式
适用场景
如图,我们可以用这种前缀表达式: (|A, (&B, C, (|E, F, G)), (|D, (&H, I))) 对逻辑如上逻辑节点进行表达
概念
我们将节点ID代表节点,节点ID可以是数字或字母
两个概念: 条件 和 分组
条件一定存在于分组中
条件之间存在 且 和 或的关系
例如一个简单的分组
(&1, 2) 那么说明 条件1 和 条件2 为且的关系
(|1, 2) 那么说明 条件1 和 条件2 为或的关系
子分组 和 条件也存在逻辑关系
例如:(&1, 2, (|3, 4))
那么 条件1 和 条件2 和 子分组(3, 4) 的关系为且,有且仅当条件1、条件2和子分组的条件同时成立,该输出项才输出 true
解析算法
测试用例1:(&10,20,30,(|4,5,6),(&7,8,9))
测试用例2:(&(|3),20,(&5,6,7))
测试用例3:(&(|A),B,(&C,D,E))
测试用例4:(|A, (&B, C, (|E, F, G)), (|D, (&H, I)))
逻辑式解析为对象的方法:
function logicExpression2Object (str) {
try {
let at = 0
let ch = ''
let next = function () {
ch = str.charAt(at)
at += 1
while (ch && ch.trim() === '') {
next()
}
return ch
}
let group = function () {
let newGroup = {
_logic: void 0,
_values: []
}
next('(')
newGroup._logic = value()
while (ch !== ')') {
newGroup._values.push(value())
}
next(')')
return newGroup
}
let and = function () {
let r = ch
next()
return r
}
let or = function () {
let r = ch
next()
return r
}
let strings = function () {
let chars = ''
while (/\w/.test(ch)) {
chars += ch
next()
}
return chars
}
let number = function () {
/** 只考虑无符号整型数字字符 */
let chars = ''
while (/\d/.test(ch)) {
chars += ch
next()
}
return chars
}
let value = function () {
switch (ch) {
case '(':
return group()
case '&':
return and()
case '|' :
return or()
case ',':
next()
return value()
default:
if (/\d/.test(ch)) {
return number()
} else if (/\w/.test(ch)) {
return strings()
} else {
throw new Error('逻辑式不合法,解析出错')
}
}
}
next()
return value()
} catch (e) {
console.error(e)
return void 0
}
}
logicExpression2Object('(|A, (&B, C, (|E, F, G)), (|D, (&H, I)))')
// {_logic: "|", _values: Array(3)}
// _logic: "|"
// _values: (3) ["A", {…}, {…}]
// __proto__: Object
对象抽象为逻辑式的方法:
function object2LogicExpression (obj) {
let result = '('
// _groupId 仅前端数据结构使用,方便进行单通道标注,不与数据库同步
let {_logic, _values} = obj
result += _logic
for (let i = 0; i < _values.length; i++) {
let value = _values[i]
if (typeof value === 'string') {
result += value
} else {
result += this.object2LogicExpression(value)
}
if (!(i === _values.length - 1)) {
result += ','
}
}
result += ')'
return result
}
object2LogicExpression(logicExpression2Object('(|A, (&B, C, (|E, F, G)), (|D, (&H, I)))'))
// (|A,(&B,C,(|E,F,G)),(|D,(&H,I)))
Caveat
从存储上看,这种数据结构较JSON结构轻量不少
以(&A, B) 为例
JSON需要{ "logic": "&", values: ["A", "B"] } 这么多字符
但是,从可读性和易用性的角度来看,Json 结构更符合多人协作的场景
Creator
广告
字节跳动招人啦,欢迎牛逼的同学加入我们,我在互娱-影像前端等你哦~