SOURCE


function readNumber(i, chars) {
    let group = []
    while(i < chars.length) {
        const val = chars[i]
        if(/(\d|\.)/.test(val)) {
            group.push(val)
            i += 1
        } else {
            break
        }
    }
    return group.join('')
}

function readPlaceholder(i, chars) {
    let group = []
    while(i < chars.length) {
        const val = chars[i]
        if (val !== '}') {
            group.push(val)
            i += 1
        } else {
            group.push('}')
            break
        }
    }
    return group.join('')
}

function parse(exp) {
    const chars = exp.split('')
    const tokens = []
    let i = 0;
    while(i < chars.length) {
        let char = chars[i]
        if (/^\d$/.test(char)) {
            const val = readNumber(i, chars)
            i += val.length
            tokens.push({
                type: 'num',
                value: Number(val)
            })
        } else if (char === '#') {
            const val = readPlaceholder(i, chars)
            i += val.length
            tokens.push({
                type: 'ph',
                value: val
            })
        } else if (/[\+\-\*\/%\(\)]/.test(char)) {
            i += 1
            const priorityMap = {
                '+': 1,
                '-': 1,
                '*': 2,
                '/': 2,
                '%': 2,
                '(': 3,
                ')': 3
            }
            tokens.push({
                type: 'op',
                value: char,
                priority: priorityMap[char] 
            })
        } else {
            i += 1
        }
    }
    return tokens
}


function evalExp(exp) {
    const tokens = parse(exp)
    let results = []
    const opStack = []
    for (let i = 0; i < tokens.length; i++) {
        const token = tokens[i]
        if (['ph', 'num'].includes(token.type)) {
            results.push(token)
        } else if (token.type === 'op') {
            let topOp = opStack[opStack.length - 1]
            if (!topOp || topOp.priority < token.priority) {
                if (token.value !== ')') {
                    opStack.push(token)
                } else {
                    while(topOp && topOp.value !== '(') {
                        results.push(topOp)
                        opStack.pop()
                        topOp = opStack[opStack.length - 1]
                    }
                    if (topOp) {
                        opStack.pop()
                    } else {
                        console.log('表达式不合法')
                        results = []
                        break
                    }
                }
            } else {
                while(topOp && topOp.value !== '(' && topOp.priority >= token.priority) {
                    results.push(topOp)
                    opStack.pop()
                    topOp = opStack[opStack.length - 1]
                }
                opStack.push(token)
            }
        }
    }
    if (opStack.length) {
        let topOp = opStack.pop()
        while(topOp) {
            results.push(topOp)
            topOp = opStack.pop()
        }
    }
    console.log('===results', results.map(i => i.value))
    let numStack = []
    for (let i = 0; i < results.length; i++) {
        const token = results[i]
        if (token.type === 'num') {
            numStack.push(token.value)
        } else {
            const b = numStack.pop()
            const a = numStack.pop()
            if (a != null && b != null) {
                if (token.value === '+') {
                    numStack.push(a + b)
                } else if (token.value === '-') {
                    numStack.push(a - b)
                } else if (token.value === '*') {
                    numStack.push(a * b)
                } else if (token.value === '/') {
                    if (!b) {
                        numStack = []
                        break
                    } else {
                        numStack.push(a / b)
                    }
                } else if (token.type === '%') {
                    number.push(a % b)
                }
            }
        }
    }
    if (numStack.length !== 1) {
        console.log('====numStack', numStack)
        return ''
    }
    return numStack[0]
}

console.log(evalExp('107.5 * (3 * 4 + 3)'))
console 命令行工具 X clear

                    
>
console