刘光辉
14 小时以前 0dfe84494048ce27ba8449831782128412d3eb13
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
 * 将用户输入的连续单个数字合并为一个数
 * @param {Array} expressions - 记录计算表达式的数组
 * @returns {Array} 新的数组
 */
export const mergeNumberOfExps = (expressions) => {
  const res: any = [];
  const isNumChar = (n) => /^[\d|.]$/.test(n);
  for (let i = 0; i < expressions.length; i++) {
    if (i > 0 && isNumChar(expressions[i - 1]) && isNumChar(expressions[i])) {
      res[res.length - 1] += expressions[i];
      continue;
    }
    res.push(expressions[i]);
  }
  return res;
};
/**
 * 校验表达式是否符合计算法则
 * @param {Array} expressions - 合并数字后的表达式数组
 * @returns {boolean}
 */
export const validExp = (expressions, mergeNum = true) => {
  const temp = mergeNum ? mergeNumberOfExps(expressions) : expressions;
  const arr = temp.filter((t) => !'()'.includes(t));
  // 去括号后 length应该为奇数  并且第一个字符和最后一个字符应该为数字而非计算符号
  if (temp.length % 2 === 0 || arr.length % 2 === 0 || Number.isNaN(+arr[0]) || Number.isNaN(+arr[arr.length - 1])) {
    return false;
  }
  for (let i = 0; i < arr.length - 1; i += 2) {
    if (typeof +arr[i] !== 'number' || !Number.isNaN(+arr[i + 1])) return false;
  }
  return true;
};
export const validDateExp = (expressions, mergeNum = true) => {
  const temp = mergeNum ? mergeNumberOfExps(expressions) : expressions;
  // length应该3的倍数、 以+/-号开头、以y/m/d/h/m/s结尾、中间应该为数字
  if (temp.length % 3 !== 0) {
    return false;
  }
  for (let i = 0; i < temp.length - 1; i += 3) {
    if (/^\+\d+|-\d+$/.test(temp[i]) || Number.isNaN(+temp[i + 1])) return false;
  }
  return true;
};
/**
 * 校验日期计算表达式是否符合计算法则
 * @param {Array} expressions - 合并数字后的表达式数组
 * @returns {boolean}
 */
/**
 * 中缀转后缀(逆波兰 Reverse Polish Notation)
 * @param {Array} exps - 中缀表达式数组
 */
export const toRPN = (exps) => {
  const s1: any[] = []; // 符号栈
  const s2: any[] = []; // 输出栈
  const getTopVal = (stack) => (stack.length > 0 ? stack[stack.length - 1] : null);
  const levelCompare = (c1, c2) => {
    const getIndex = (c) => ['+-', '×÷', '()'].findIndex((t) => t.includes(c));
    return getIndex(c1) - getIndex(c2);
  };
  exps.forEach((t) => {
    if (typeof t === 'string' && Number.isNaN(Number(t))) {
      // 是符号
      if (t === '(') {
        s1.push(t);
      } else if (t === ')') {
        let popVal;
        do {
          popVal = s1.pop();
          popVal !== '(' && s2.push(popVal);
        } while (s1.length && popVal !== '(');
      } else {
        let topVal = getTopVal(s1);
        if (topVal) {
          while (topVal && topVal !== '(' && levelCompare(topVal, t) >= 0) {
            // 优先级 >= t 弹出到s2
            s2.push(s1.pop());
            topVal = getTopVal(s1);
          }
          s1.push(t);
        } else {
          // s1 为空 直接push
          s1.push(t);
        }
      }
      return;
    }
    s2.push(t); // 数字直接入栈
  });
  while (s1.length) {
    s2.push(s1.pop());
  }
  return s2;
};
/**
 * 计算后缀表达式的值
 * @param {Array} rpnExps - 后缀表达式
 */
export const calcRPN = (rpnExps) => {
  rpnExps = [...rpnExps];
  const calc = (x, y, type) => {
    const a1 = Number(x);
    const a2 = Number(y);
    switch (type) {
      case '+': {
        return a1 + a2;
      }
      case '-': {
        return a1 - a2;
      }
      case '÷': {
        return a1 / a2;
      }
      case '×': {
        return a1 * a2;
      }
    }
  };
  for (let i = 2; i < rpnExps.length; i++) {
    if ('+-×÷'.includes(rpnExps[i])) {
      const val = calc(rpnExps[i - 2], rpnExps[i - 1], rpnExps[i]);
      rpnExps.splice(i - 2, 3, val);
      i = i - 2;
    }
  }
  return rpnExps[0];
};