Inputting a Equation in Textfield and Processing it? [actionscript 3.0]

Go To StackoverFlow.com

1

I would like to know if theirs a way where you can type in a text field something like "5*5".

And then on enter, the document would take the database and be able to return 25.

I am quite confused due to the fact that content that you input into a textfield must be a String and when you use the Number() converter the system gets confused.

2012-04-03 23:19
by Cyrus Kafai Wu
You can parse the string and look for operators like + - * and / and then perform the correct operation on the numbers on either side of those operators - M. Laing 2012-04-04 00:11


1

You'll need to break your string apart at operators (using regex) and then keep those operators.

I don't have the patience to do this myself but you'll need to prioritise certain operations as well (multiplication before addition, etc).

I've done some code to get you started - note that it only works with really simple algorithms in its current form:

// Finds +, - and *.
var operators:RegExp = /\+|\-|\*/g;
var numbers:RegExp = /\d+/g;


/**
 * Attempts to work with a mathematical formula provided as string.
 * @param str Subject string.
 */
function work(str:String):Number
{
    var ops:Array = str.match(operators);   // List of operators in order.
    var nums:Array = str.match(numbers);    // List of numbers in order.

    var command:Array = [];
    var cmbLen:int = Math.max(ops.length, nums.length);

    for(var i:int = 0; i < cmbLen; i++)
    {
        if(nums[i]) command.push(nums[i]);
        if(ops[i]) command.push(ops[i]);
    }


    // Begin performing the command.
    var val:Number = 0;
    var queuedOperator:String = "";

    for(i = 0; i < command.length; i++)
    {
        // Apply initial value;
        if(i == 0)
            val = Number(command[i]);

        // Work.
        if(i % 2 == 0)
        {
            var num:Number = Number(command[i]);

            // Operate if required.
            if(queuedOperator.length > 0)
            {
                switch(queuedOperator)
                {
                    case "+": val += num; break;
                    case "-": val -= num; break;
                    case "*": val *= num; break;
                }
            }

            queuedOperator = command[i + 1] as String || "";
        }
    }

    return val;
}

And some testing:

trace(work("7 + 10")); // 17
trace(work("5 * 5")); // 25
trace(work("12 - 4")); // 8

trace(work("10 + 5 + 1")); // 16

Feel free to build on this to include more operators (just add them into operators) and sort the command in order of priority. Adding () parenthesis will start to get interesting but with time I'm sure it's possible to get working right.

2012-04-04 00:43
by Marty


0

Here's another solution using RegExp. This can calculate whole and decimal numbers using the following signs: ^,%,/,*,+,-. You can also use parantheses e.g. 2^(10/(2+3-2)).

You will need to select the disable keyboard shortcuts option from the control menu when in test movie mode to see the result.

import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;


var tf:TextField = new TextField();
tf.addEventListener(KeyboardEvent.KEY_DOWN,tfKeyDown);
tf.defaultTextFormat = new TextFormat('_sans',24);
tf.autoSize = TextFieldAutoSize.LEFT;
tf.wordWrap = true;
tf.type = TextFieldType.INPUT;
tf.border = true;
tf.x = (stage.stageWidth - 300) * .5;
tf.y = 100;
tf.width = 200;
addChild(tf);
stage.focus = tf;


function tfKeyDown(e:KeyboardEvent):void {
    if (e.keyCode == Keyboard.ENTER) {
        e.preventDefault();
        trace('Input:',tf.text);
        trace('Result:',calculate(tf.text,7));
        trace('-----------------------');
    }
}

function calculate(str:String,maxDecimalCount:int=int.MAX_VALUE):Number {

    var num:String = '-?[0-9]*\\.?[0-9]+';
    var numRX:RegExp = new RegExp(num,'g');
    var rx:RegExp, i:int;

    // normalize minuses and eliminate spaces
    str = str.replace(/--/g,'+').replace(/\s/g,'');

    // calculate parenthesized equations
    while (/\(([^\(\)]+)\)/.test(str)) {
        str = str.replace(/\(([^\(\)]+)\)/g,function() {
            return calculate(String(arguments[1]),int.MAX_VALUE).toString();
        });
    }

    // exponential --> x^y
    rx = new RegExp(num+'(\\^'+num+')+','g');
    str = str.replace(rx,function() {
        var nums = String(arguments[0]).match(numRX);
        var res:Number = Math.pow(Number(nums[0]),Number(nums[1]));
        for (i = 2; i < nums.length; i++) res = Math.pow(res,Number(nums[i]));
        //trace('^ ['+nums+'] =',res);
        return res;
    });
    // modulus --> x%y
    rx = new RegExp(num+'(%'+num+')+','g');
    str = str.replace(rx,function() {
        var nums = String(arguments[0]).match(numRX);
        var res:Number = Number(nums[0]);
        for (i = 1; i < nums.length; i++) res %= Number(nums[i]);
        //trace('% ['+nums+'] =',res);
        return res;
    });
    // divide --> x/y
    rx = new RegExp(num+'(/'+num+')+','g');
    str = str.replace(rx,function() {
        var nums = String(arguments[0]).match(numRX);
        var res:Number = Number(nums[0]);
        for (i = 1; i < nums.length; i++) res /= Number(nums[i]);
        //trace('/ ['+nums+'] =',res);
        return res;
    });
    // multiply --> x*y
    rx = new RegExp(num+'(\\*'+num+')+','g');
    str = str.replace(rx,function() {
        var nums = String(arguments[0]).match(numRX);
        var res:Number = Number(nums[0]);
        for (i = 1; i < nums.length; i++) res *= Number(nums[i]);
        //trace('* ['+nums+'] =',res);
        return res;
    });
    // add or subtract --> x+y or x-y
    rx = new RegExp(num+'([\\+\\-]'+num+')+','g');
    str = str.replace(rx,function() {
        var nums = String(arguments[0]).match(numRX);
        var res:Number = Number(nums[0]);
        for (i = 1; i < nums.length; i++) res += Number(nums[i]);
        //trace('+- ['+nums+'] =',res);
        return res;
    });

    var res:Number = Number(str);
    // if the result is not a number...
    if (isNaN(res)) {
        throw new Error('Please input a valid equation using numbers and the following signs: ()^%/*+-');
    }
    // if the remainder needs to be shortened...
    if (maxDecimalCount < int.MAX_VALUE &&
        int(res) != res && String(res).split('.')[1].length > maxDecimalCount) {
        res = Math.round(res * Math.pow(10,maxDecimalCount)) / Math.pow(10,maxDecimalCount);
    }
    return res; 

}
2012-04-04 03:10
by inhan
I'm not sure where modulus and exponential should be in the order, though. That might need a change - inhan 2012-04-05 12:48