Home > front end >  How to convert this code from JavaScript to Dart?
How to convert this code from JavaScript to Dart?

Time:10-28

I want to write code in dart that can calculate like this expression: 100 * ( 2 12 ) / 14 (infix notation) taking into consideration the priority of operators. for ex: "*" is stronger than " ". The code below fixes my issue but it's written in JavaScript, I tried to convert it to dart but I am stuck.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infix Notation</title>
</head>
<body>
    <script>
        function evaluate(expression){
            let tokens = expression.split(' ');
            // Stack for numbers: 'values'
            let values = [];
            // Stack for Operators: 'ops'
            let ops = [];
    
            for (let i = 0; i < tokens.length; i  ){
                if (tokens[i] >= '0' && tokens[i] <= '9'){
                    let number = "";
                    // There may be more than one digits in number
                    while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9'){
                        number = number   tokens[i  ];
                    }

                    document.write(number   "</br>");
                    values.push(parseInt(number, 10));
                    
                    // Right now the i points to
                    // the character next to the digit,
                    // since the for loop also increases
                    // the i, we would skip one
                    // token position; we need to
                    // decrease the value of i by 1 to
                    // correct the offset.
                    i--;
                }
    
                // Current token is an opening
                // brace, push it to 'ops'
                else if (tokens[i] == '(')
                {
                    ops.push(tokens[i]);
                }
    
                // Closing brace encountered,
                // solve entire brace
                else if (tokens[i] == ')')
                {
                    while (ops[ops.length - 1] != '(')
                    {
                    values.push(applyOp(ops.pop(),
                                    values.pop(),
                                    values.pop()));
                    }
                    ops.pop();
                }
    
                // Current token is an operator.
                else if (tokens[i] == ' ' ||
                        tokens[i] == '-' ||
                        tokens[i] == '*' ||
                        tokens[i] == '/')
                {
                    
                    // While top of 'ops' has same
                    // or greater precedence to current
                    // token, which is an operator.
                    // Apply operator on top of 'ops'
                    // to top two elements in values stack
                    while (ops.length > 0 &&
                            hasPrecedence(tokens[i],
                                        ops[ops.length - 1]))
                    {
                    values.push(applyOp(ops.pop(),
                                    values.pop(),
                                    values.pop()));
                    }
    
                    // Push current token to 'ops'.
                    ops.push(tokens[i]);
                }
            }
    
            // Entire expression has been
            // parsed at this point, apply remaining
            // ops to remaining values
            while (ops.length > 0){
                values.push(applyOp(ops.pop(),
                                values.pop(),
                                values.pop()));
            }
    
            // Top of 'values' contains
            // result, return it
            return values.pop();
        }
    
        // Returns true if 'op2' has
        // higher or same precedence as 'op1',
        // otherwise returns false.
        function hasPrecedence(op1, op2){
            if (op2 == '(' || op2 == ')')
            {
                return false;
            }
            if ((op1 == '*' || op1 == '/') &&
                (op2 == ' ' || op2 == '-'))
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    
        // A utility method to apply an
        // operator 'op' on operands 'a'
        // and 'b'. Return the result.
        function applyOp(op, b, a){
            switch (op)
            {
            case ' ':
                return a   b;
            case '-':
                return a - b;
            case '*':
                return a * b;
            case '/':
                if (b == 0)
                {
                    document.write("Cannot divide by zero");
                }
                return parseInt(a / b, 10);
            }
            return 0;
        }
        document.write(evaluate("10,5   2 * 6")   "</br>");
        document.write(evaluate("100 * 2   12")   "</br>");
        document.write(evaluate("100 * ( 2   12 )")   "</br>");
        document.write(evaluate( "100 * ( 2   12 ) / 14")   "</br>");
    
    // This code is contributed by decode2207.
    </script>
    
</body>
</html>

In dart there is no built in function for stack so we have to write its class in order to use push(), pop(), length.. as below:

class Values<T> {
  final _list = <T>[];
  void push(T value) => _list.add(value);
  T pop() => _list.removeLast();
  T get top => _list.last;
  bool get isEmpty => _list.isEmpty;
  bool get isNotEmpty => _list.isNotEmpty;
  int get length => _list.length;
  T get peek => _list.last;
  @override
  String toString() => _list.toString();
}

CodePudding user response:

1. Closest translation to Dart with some refactoring (personal advice: don't use this past simple use cases, like the ones in the examples above)

num evaluate(String expression) {
  var tokens = expression.split(' ');
  // Stack for numbers: 'values'
  List<num> values = [];
  // Stack for Operators: 'ops'
  List<String> ops = [];

  for (var i = 0; i < tokens.length; i  ) {
    if (num.tryParse(tokens[i]) != null) {
      // dart reafctor: removed the while loop here as it is not needed and bad
      values.add(num.parse(tokens[i]));
    }

    // Current token is an opening
    // brace, push it to 'ops'
    else if (tokens[i] == '(') {
      ops.add(tokens[i]);
    }

    // Closing brace encountered,
    // solve entire brace
    else if (tokens[i] == ')') {
      while (ops.last != '(') {
        values.add(applyOp(
            ops.removeLast(), values.removeLast(), values.removeLast()));
      }
      ops.removeLast();
    }

    // Current token is an operator.
    else if (tokens[i] == ' ' ||
        tokens[i] == '-' ||
        tokens[i] == '*' ||
        tokens[i] == '/') {
      // While top of 'ops' has same
      // or greater precedence to current
      // token, which is an operator.
      // Apply operator on top of 'ops'
      // to top two elements in values stack
      
      while (ops.isNotEmpty && hasPrecedence(tokens[i], ops.last)) {
        values.add(applyOp(
            ops.removeLast(), values.removeLast(), values.removeLast()));
      }

      // Push current token to 'ops'.
      ops.add(tokens[i]);
    }
  }

  // Entire expression has been
  // parsed at this point, apply remaining
  // ops to remaining values
  while (ops.isNotEmpty) {
    values.add(
        applyOp(ops.removeLast(), values.removeLast(), values.removeLast()));
  }

  // Top of 'values' contains
  // result, return it
  return values.removeLast();
}

bool hasPrecedence(String op1, String op2) {
  if (op2 == '(' || op2 == ')') {
    return false;
  }
  if ((op1 == '*' || op1 == '/') && (op2 == ' ' || op2 == '-')) {
    return false;
  } else {
    return true;
  }
}

num applyOp(String op, num b, num a) {
  switch (op) {
    case ' ':
      return a   b;
    case '-':
      return a - b;
    case '*':
      return a * b;
    case '/':
      if (b == 0) {
        throw "Cannot divide by zero";
      }
      return a / b;
  }
  return 0;
}

Dart pad

Test cases

void main() {
  print(evaluate("100 * 2   12")); // 212
  print(evaluate("100 * ( 2   12 )")); // 1400
  print(evaluate( "100 * ( 2   12 ) / 14")); // 100
}

2. This evaluates an arithmetic expression by using Regular expression matches. So not a direct translation of your code, but will work nonetheless.

num evaluate(String expr) {
  var divAndMult =
      RegExp(r"\(?\s*(\d (?:\.\d*)?)\s*([/*])\s*(\d (?:\.\d*)?)\s*\)?");
  var addAndSub =
      RegExp(r"\(?\s*(\d (?:\.\d*)?)\s*([ -])\s*(\d (?:\.\d*)?)\s*\)?");
  
  var nextInput = expr;

  while (divAndMult.hasMatch(nextInput) || addAndSub.hasMatch(nextInput)) {
    nextInput = nextInput.replaceAllMapped(divAndMult, (match) {
      if (match[2] == "*") {
        return (num.parse(match[1]!) * num.parse(match[3]!)).toString();
      }
      return (num.parse(match[1]!) / num.parse(match[3]!)).toString();
    }).replaceAllMapped(addAndSub, (match) {
      if (match[2] == " ") {
        return (num.parse(match[1]!)   num.parse(match[3]!)).toString();
      }
      return (num.parse(match[1]!) - num.parse(match[3]!)).toString();
    });
  }
  return num.parse(nextInput);
}

This can be refactored to ease adding new operators, like so:

extension ApplyOp on Match {
 String applyOp(num Function(num a, num b) op) {
   return op(num.parse(this[1]!), num.parse(this[3]!)).toString();
 }
}

num evaluate(String expr) {
 var divMultAndModulo =
     RegExp(r"\(?\s*(\d (?:\.\d*)?)\s*([/*%])\s*(\d (?:\.\d*)?)\s*\)?");
 var addAndSub =
     RegExp(r"\(?\s*(\d (?:\.\d*)?)\s*([ -])\s*(\d (?:\.\d*)?)\s*\)?");

 var nextInput = expr;

 while (divMultAndModulo.hasMatch(nextInput) || addAndSub.hasMatch(nextInput)) {
   nextInput = nextInput.replaceAllMapped(divMultAndModulo, (match) {
     if (match[2] == "*") {
       return match.applyOp((a, b) => a * b);
     }
     if(match[2] == '%') {
       return match.applyOp((a, b) => a % b);
     }
     return match.applyOp((a, b) => a / b);
   }).replaceAllMapped(addAndSub, (match) {
     if (match[2] == " ") {
       return match.applyOp((a, b) => a   b);
     }
     return match.applyOp((a, b) => a - b);
   });
 }

 return num.parse(nextInput);
}

Test cases

void main() {
  print(evaluate("(8 * 8) - (20 / 5)   8")); // 68
  print(evaluate("( 2   12 )")); // 14
  print(evaluate("100 * ( 2   12 ) / 14")); // 100
  print(evaluate("10.5   2 * 6")); // 22.5
  print(evaluate("20 % 3")); // 2
}

Dart pad

  • Related