class ConditionParser {
ops = ['>=', '<=', '>', '=', '<', 'in', 'like', '(', ')', '&&', '||']
priority = {
'>': 3,
'>=': 3,
'=': 3,
'<': 3,
'<=': 3,
'like': 3,
'in' : 3,
'&&': 2,
'||': 1,
'(': 0,
')': 0,
}
getValue(str, token) {
str = str.trim()
if (/\{\s*([^\s]*)\s*\}/.test(str)) {
token.push({
type: 'ph',
value: RegExp.$1
})
} else if (str) {
token.push({
type: 'value',
value: str
})
}
}
parsTokens(exp) {
let tmp = exp
const token = []
const esc = (val) => val.replace(/[()|]/g, '\\$&')
const opsjoin = this.ops.map(i => esc(i)).join('|')
const tokenReg = new RegExp(`\\s*(${opsjoin})`)
while(tmp) {
let idx = tmp.search(tokenReg)
if (idx != - 1) {
const substr = tmp.slice(0, idx)
const nextIdx = RegExp['$&'].length + idx
this.getValue(substr, token)
const op = tmp.slice(idx, nextIdx).trim()
token.push({
type: 'op',
value: op,
priority: this.priority[op]
})
tmp = tmp.slice(nextIdx)
} else {
this.getValue(tmp, token)
tmp = ''
}
}
return token
}
parse(exp) {
const tokens = this.parsTokens(exp)
const result = []
const stack = []
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i]
if (/(value|ph)/.test(token.type)) {
result.push(token)
} else if (token.value === '(') {
stack.push(token)
} else if (token.value === ')') {
let top = stack.pop()
while(top && top.value !== '(') {
result.push(top)
top = stack.pop()
}
if (!top) {
console.log('括号不匹配')
stack = []
result = []
break;
}
} else {
const top = stack[stack.length - 1]
if (!top || top.priority < token.priority) {
stack.push(token)
} else if (top && top.priority >= token.priority) {
result.push(top)
stack.pop()
stack.push(token)
}
}
}
while(stack.length) {
const top = stack.pop()
if (top.value === '(' || top.value === ')') {
console.log('括号不匹配')
stack = []
result = []
break
} else {
result.push(top)
}
}
return this.buildCriteria(result)
}
buildCriteria(list) {
let criterias = []
let ops = []
for (let i = 0; i < list.length; i++) {
const token = list[i]
if (token.type !== 'op') {
ops.push(token)
} else {
if (!['&&', '||'].includes(token.value)) {
if (ops.length < 2) {
console.log('表达式不合法')
return null
} else {
const right = ops.pop()
const left = ops.pop()
if (token.value == '>') {
criterias.push(`Critera.where("${left.value}").gt(${Number(right.value) || 0})`)
} else if (token.value === '>=') {
criterias.push(`Critera.where("${left.value}").gte(${Number(right.value) || 0})`)
} else if (token.value === '<') {
criterias.push(`Critera.where("${left.value}").lt(${Number(right.value) || 0})`)
} else if (token.value === '<=') {
criterias.push(`Critera.where("${left.value}").lte(${Number(right.value) || 0})`)
} else if (token.value === '=') {
criterias.push(`Critera.where("${left.value}").eq(${Number(right.value) || 0})`)
} else if (token.value === 'in') {
criterias.push(`Critera.where("${left.value}").in(Arrays.asList("${right.value}".split(",")))`)
} else if (token.value === 'like') {
criterias.push(`Critera.where("${left.value}").regx()`)
}
}
} else {
if (criterias.length < 2) {
console.log('表达式不合法')
return null
}
const r = criterias.pop()
const l = criterias.pop()
if (token.value === '&&') {
criterias.push(`new Criteria().andOperator(\n${l}, \n${r}\n)`)
} else if (token.value === '||') {
criterias.push(`new Criteria().orOperator(\n${l}, \n${r}\n)`)
}
}
}
}
return criterias[0]
}
}
const exp = '{deptIds} in 1,2,3 && projectStatus in 4,5'
const d = new ConditionParser()
console.log(exp)
console.log(d.parse(exp))
console