| 30 | "*": { precedence: 2 }, |
| 31 | "/": { precedence: 2 }, |
| 32 | }; |
| 33 | |
| 34 | private static tokenize(expr: string): string[] { |
| 35 | const cleaned = expr.replace(/\s+/g, ""); |
| 36 | if (!cleaned) { |
| 37 | throw new Error("表达式为空"); |
| 38 | } |
| 39 | if (!/^[0-9+\-*/().]+$/.test(cleaned)) { |
| 40 | throw new Error("表达式包含不支持的字符"); |
| 41 | } |
| 42 | |
| 43 | const tokens: string[] = []; |
| 44 | let current = ""; |
| 45 | |
| 46 | const pushCurrent = () => { |
| 47 | if (!current) return; |
| 48 | if (!this.isNumber(current)) { |
| 49 | throw new Error(`无效的数字: ${current}`); |
| 50 | } |
| 51 | tokens.push(current); |
| 52 | current = ""; |
| 53 | }; |
| 54 | |
| 55 | const isUnaryPosition = (index: number) => |
| 56 | index === 0 || cleaned[index - 1] === "(" || cleaned[index - 1] in this.operators; |
| 57 | |
| 58 | for (let i = 0; i < cleaned.length; i++) { |
| 59 | const char = cleaned[i]; |
| 60 | |
| 61 | if (/[0-9.]/.test(char)) { |
| 62 | current += char; |
| 63 | continue; |
| 64 | } |
| 65 | |
| 66 | pushCurrent(); |
| 67 | |
| 68 | if ((char === "-" || char === "+") && isUnaryPosition(i)) { |
| 69 | if (char === "-") { |
| 70 | if (i + 1 < cleaned.length && cleaned[i + 1] === "(") { |
| 71 | tokens.push("-1"); |
| 72 | tokens.push("*"); |
| 73 | continue; |
| 74 | } |
| 75 | current = "-"; |
| 76 | } |
| 77 | continue; |
| 78 | } |
| 79 | |
| 80 | if (!(char in this.operators) && char !== "(" && char !== ")") { |
| 81 | throw new Error(`未知操作符: ${char}`); |
| 82 | } |
| 83 | |
| 84 | tokens.push(char); |
| 85 | } |
| 86 | |
| 87 | pushCurrent(); |
| 88 | return tokens; |
| 89 | } |