话不多说,快上码!
TODO:
- 返回具体探测到的某个 item
/**
* @method checkBracketPairs
* 解决的核心问题是: 括号边界的匹配,即检测起始和结束时的边界问题,每个起始必须匹配存在且正确的边界
* @description 检测括号的算法
* 1. 开始括号永远是前置(先)存在,然后才有结束括号
* 2. 开始括号的标志位永远存在结束括号对应的标志位
* 3. 条件自身即存在开始又存在结束,则不用处理类似(a)+(b)括号了自身
* @example right:
* 0. a || b
* 1. (a && b) || c
* 2. a || (b && c)
* 3. ((a && b) || c) && d || e
* 4. (((a && b) || c) && d) || e
* 5. ((a && b) || c) && (d || e)
* @example wrong:
* 0. a) // or `(b`
* 1. (a || b // or `a || b)`
* @param {Array<{ leftBracket?: boolean, rightBracket?: boolean, [prop: string]: any }>} items
* @returns {void|Error}
*/
export const checkBracketPairs = (items) => {
// 开始括号栈 => FILO 先入后出(push => 入, pop => 尾出)
const leftStack = []
// 结束括号队列 => FIFO 先入先出(push => 入, shift => 顶出)
const rightQueue = []
// 开始括号栈指针 flag
let leftPointer = 0
// 结束括号栈指针 flag
let rightPointer = 0
let i = 0
const last = items.length
const graphMap = new Map()
if (items.length) {
do {
leftPointer = leftStack.length
rightPointer = rightQueue.length
const condition = items[i++]
// leftBracket
if (condition.leftBracket) {
// 入栈并记录标志位
leftPointer = leftStack.push(condition)
}
// rightBracket
if (condition.rightBracket) {
// 入栈并记录标志位
rightPointer = rightQueue.push(condition)
if (leftPointer) {
// 左括号出栈,对应最新的 第一个右括号
const l = leftStack.pop()
// 右括号出列,对应其匹配的左括号
const r = rightQueue.shift()
if (l && r) {
// 用图记录其位置 { l: r }
graphMap.set(l, r)
}
} else {
// 无左括号 => Error
throw Error('无法找到匹配的左括号')
}
}
// 依然存在右括号,而没有左括号
if (!leftPointer && rightPointer) {
throw Error('无法找到匹配的左括号')
}
// 依然存在左括号,而没有右括号
if (leftPointer > rightPointer && i === last) {
throw Error('无法找到匹配的右括号')
}
} while (i < last)
}
}