JS 检测括号边界匹配算法的简单实现

话不多说,快上码!

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)
  }
}
posted @ 2019-10-23 15:04  月光宝盒造梦师  阅读(979)  评论(0编辑  收藏  举报