You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript自定义类似eval函数:连续减号操作bug求助

Fixing the Consecutive '-' Operator Bug in a Custom eval() Function

Hey there! It sounds like you're making great progress on building your custom expression evaluator in JavaScript—nice work getting most operations running smoothly! The issue with consecutive '-' operators is a super common pitfall when parsing expressions, since '-' can act as both binary subtraction (like 5 - 3) and unary negation (like -3 or 5--3). Let's break down how to fix this.

Why the Bug Happens

Most basic parsers treat '-' as a single type of operator, but in reality, its role depends on context:

  • If '-' comes right after an operator, at the start of the string, or after an opening parenthesis (, it's a unary operator (negates the value that follows).
  • Otherwise, it's a binary operator (subtracts the right operand from the left).

If your current code doesn't make this distinction, it'll see something like "5--3" as two back-to-back binary subtraction operators—with no operand in between—leading to errors or wrong calculations.

Step-by-Step Fix

Let's adjust your tokenization and parsing logic to handle unary negation properly:

1. Improve Tokenization to Identify Unary Minuses

First, update your tokenizer to mark '-' as a unary operator when it appears in the right context:

function tokenize(expr) {
  const tokens = [];
  let numBuffer = '';
  
  for (let i = 0; i < expr.length; i++) {
    const char = expr[i];
    
    // Build numbers (including decimals)
    if (/\d|\./.test(char)) {
      numBuffer += char;
    } else {
      // Push the completed number token if we have one
      if (numBuffer) {
        tokens.push({ type: 'number', value: parseFloat(numBuffer) });
        numBuffer = '';
      }
      
      // Check if this '-' is a unary operator
      if (char === '-' && (
        i === 0 || 
        tokens.length === 0 || 
        ['+', '-', '*', '/', '('].includes(tokens.at(-1).type)
      )) {
        tokens.push({ type: 'unary-minus', value: '-' });
      } else {
        // Treat as regular binary operator
        tokens.push({ type: 'operator', value: char });
      }
    }
  }
  
  // Push the final number token if any
  if (numBuffer) {
    tokens.push({ type: 'number', value: parseFloat(numBuffer) });
  }
  
  return tokens;
}

2. Update Parsing to Handle Unary Negation

Next, modify your expression evaluation logic to give unary minus higher precedence than binary subtraction (just like native JavaScript does). A recursive descent parser works well here—add a function to handle unary operations first:

function evaluateUnary(tokens, currentIndex) {
  const token = tokens[currentIndex];
  
  // Handle unary minus: negate the next expression
  if (token.type === 'unary-minus') {
    const { value: innerValue, newIndex } = evaluateUnary(tokens, currentIndex + 1);
    return { value: -innerValue, newIndex };
  }
  
  // Handle numbers or parenthesized expressions
  if (token.type === 'number') {
    return { value: token.value, newIndex: currentIndex + 1 };
  }
  if (token.value === '(') {
    const { value: innerValue, newIndex } = evaluateExpression(tokens, currentIndex + 1);
    // Skip the closing parenthesis
    return { value: innerValue, newIndex: newIndex + 1 };
  }
  
  throw new Error(`Unexpected token at position ${currentIndex}`);
}

// Your existing evaluateExpression function would call evaluateUnary first,
// then handle binary operators like +, -, *, /

Test Edge Cases

Make sure to validate these scenarios to ensure the fix works:

  • "5--3" should evaluate to 8 (equivalent to 5 - (-3))
  • "--10" should evaluate to 10
  • "-5 + 7" should evaluate to 2
  • "3 * -4" should evaluate to -12

内容的提问来源于stack exchange,提问作者Raj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:37:32