目录
解析数学表达式
字符串解码/智能重复
解析数学表达式
const stock = []; // 先进后出,每一次出栈,即一对 ()
const parenthesesPairPosition = {}
// 剔除两侧空格
const removeBlank = (expression, l, r) => {
while (expression[l] === ' ') {
l++
}
while (expression[r] === ' ') {
r--
}
return [l, r]
}
// 剔除两侧小括号
const removeParentheses = (l, r) => {
if (parenthesesPairPosition[l] === r) return [++l, --r]
return [l, r]
}
const parse = (expression, l = 0, r = expression.length - 1, skipSearchTimeOrDivide = false) => {
let isNumber = true;
let parenthesesDep = 0; // 记录小括号深度
let firstTimeOrDivideOperator = null; // 记录遇到的第一个 * / 运算符
let firstTimeOrDivideOperatorIdx = null; // 记录遇到的第一个 * / 运算符的位置
[l, r] = removeBlank(expression, l, r);
[l, r] = removeParentheses(l, r);
for (let i = r; i >= l; i--) {
const v = expression[i];
if (v === ')') {
stock.push(i)
parenthesesDep++
} else if (v === '(') {
const last = stock.pop()
parenthesesPairPosition[i] = last
parenthesesDep--
}
// skipSearchTimeOrDivide 为 true 表示表达式是连续的 * /
if (skipSearchTimeOrDivide && firstTimeOrDivideOperator) {
return {
type: firstTimeOrDivideOperator,
left: parse(expression, l, firstTimeOrDivideOperatorIdx - 1, true),
right: parse(expression, firstTimeOrDivideOperatorIdx + 1, r),
}
}
if (i === l) {
if (isNumber) {
return {
type: 'number',
value: Number(expression.slice(l, r + 1).trim()),
};
}
if (parenthesesPairPosition[i] === r) {
return parse(expression, l + 1, r - 1)
}
// * / 拆分,需要遍历到最左侧,所里拆分逻辑写这里
return {
type: firstTimeOrDivideOperator,
left: parse(expression, l, firstTimeOrDivideOperatorIdx - 1, true),
right: parse(expression, firstTimeOrDivideOperatorIdx + 1, r),
}
}
if (/[0-9.]/.test(v) || v === ' ') {
continue;
}
isNumber = false;
// parenthesesDep === 0 进行表达式分析的时候要确保是同一层级
if (parenthesesDep === 0 && (v === '+' || v === '-')) {
return {
type: v,
left: parse(expression, l, i - 1),
right: parse(expression, i + 1, r),
}
}
if (parenthesesDep === 0 && (v === '*' || v === '/') && !firstTimeOrDivideOperator) {
firstTimeOrDivideOperator = v
firstTimeOrDivideOperatorIdx = i
}
}
}
const exec = ast => {
const recursion = ast => {
if (ast.type === '+') {
return recursion(ast.left) + recursion(ast.right)
} else if (ast.type === '-') {
return recursion(ast.left) - recursion(ast.right)
} else if (ast.type === '*') {
return recursion(ast.left) * recursion(ast.right)
} else if (ast.type === '/') {
return recursion(ast.left) / recursion(ast.right)
} else if (ast.type === 'number') {
return ast.value
}
}
return recursion(ast)
}
let expression = '(1 + (2 - (3 * 4 / 5 + 6 - (7 + 8))) + (9 - 10) * 11 + 12) + 13'
console.log(exec(parse(expression)) === eval(expression))
expression = '3.5 * 4 / 5 + 6'
console.log(exec(parse(expression)) === eval(expression))
字符串解码/智能重复
const decodeString = (s) => {
let numStack = []; // 存倍数的栈
let strStack = []; // 存 待拼接的str 的栈
let num = 0; // 倍数的“搬运工”
let result = ''; // 字符串的“搬运工”
for (const char of s) { // 逐字符扫描
if (!isNaN(char)) { // 遇到数字
num = num * 10 + Number(char); // 算出倍数
} else if (char == '[') { // 遇到 [
strStack.push(result); // result串入栈
result = ''; // 入栈后清零
numStack.push(num); // 倍数num进入栈等待
num = 0; // 入栈后清零
} else if (char == ']') { // 遇到 ],两个栈的栈顶出栈
let repeatTimes = numStack.pop(); // 获取拷贝次数
result = strStack.pop() + result.repeat(repeatTimes); // 构建子串
} else {
result += char; // 遇到字母,追加给result串
}
}
return result;
};