anon
anon

Reputation:

RegEx for a^b instead of pow(a,b)

Here's an interesting one. Anyone have a good RegEx for converting all (first) ^ (second) to Math.pow((first), (second))?

EDIT:

The best I have so far is

s = s.replace(/((?:\d+\.?\d*)|\w+|\((?:(?:[^\(\)]*(?:\([^\(\)]*\)))*)\))\s*\^\s*((?:\d+\.?\d*)|\w+|\((?:(?:[^\(\)]*(?:\([^\(\)]*\)))*)\))/g, 'Math.pow($1, $2)') // replace expression ^ expression with Math.pow($1, $2)

The answers so far are not general enough. They don't cover something like (var1 + var2)^2 let alone (var1 * (var2 + var3))^2

The solution will have to work with parentheses.

You can use strfriend.com to help visualize the regex as you make it. That's what I've been doing.

Upvotes: 5

Views: 2085

Answers (6)

Eric Hakenholz
Eric Hakenholz

Reputation: 81

var caretReplace = function(_s) {
    if (_s.indexOf("^") > -1) {
        var tab = [];
        var powfunc="Math.pow";
        var joker = "___joker___";
        while (_s.indexOf("(") > -1) {
            _s = _s.replace(/(\([^\(\)]*\))/g, function(m, t) {
                tab.push(t);
                return (joker + (tab.length - 1));
            });
        }

        tab.push(_s);
        _s = joker + (tab.length - 1);
        while (_s.indexOf(joker) > -1) {
            _s = _s.replace(new RegExp(joker + "(\\d+)", "g"), function(m, d) {
                return tab[d].replace(/(\w*)\^(\w*)/g, powfunc+"($1,$2)");
            });
        }
    }
    return _s;
};
  1. console.log(caretReplace("(3*(f(x^2)-2)^2+1^5-g(2^3+1)^5)^(9-2^3)")); gives Math.pow((3*Math.pow((f(Math.pow(x,2))-2),2)+Math.pow(1,5)-Math.pow(g(Math.pow(2,3)+1),5)),(9-Math.pow(2,3))).

  2. Your math expression must be valid, with well balanced opened and closed parentheses.

  3. You can replace Math.pow with any function name you want.

  4. I've done this by replacing all parentheses, from the most inner to the most outer, with non-math texts (___joker___0, ___joker___1, etcetera). At the end I parse all these strings hierarchically, to replace carets on non-parentheses expressions.

Upvotes: 1

matthias.lukaszek
matthias.lukaszek

Reputation: 2220

This cannot be done with regex (at least not without lots of effort). You have to consider different layers of parenthesis, which can't be handled with a simple regular expression. I suggest to look for a library capable of parsing mathematical expression. Or you'll have to restrict the possible expression to something you can handle with a simple regex.

There is the possibility to define named and balancing capture groups in a regular expression which can be used (backreferenced) in the same regular expression. With this you would have to define the desired subset of the math syntax and both captures for the parameters. I suggest you should not reinvent the wheel and use a JS library.

http://snippets.dzone.com/posts/show/2207

Upvotes: 11

Dancrumb
Dancrumb

Reputation: 27579

Take a look at Jison, a Javascript parser generator.

In particular, check out their calculator demo

Upvotes: 0

Bruno De Fraine
Bruno De Fraine

Reputation: 47366

The bad news: regular expressions won't cut it (as many answers indicate), you will need to write a parser for this.

The good news: you can relatively easily do this yourself in almost any language by writing a recursive descent parser. You should of course reuse existing code as much as possible, but coding a recursive descent parser yourself (and seeing how you encode precedence rules) can be recommended purely for the enlightening experience.

Pick up any book on compiler construction and read the first few chapters on parsing. Let me recommend this freely available book by Niklaus Wirth, look for 4.1 "The method of recursive descent".

Upvotes: 1

GK80
GK80

Reputation: 51

Assuming you want to convert source files or something like that, take a perl script running over your source files and use Math::Expression::Evaluator::Parser. From the synopsis:

use Math::Expression::Evaluator::Parser;

my $exp = '2 + a * 4';
my $ast = Math::Expression::Evaluator::Parser::parse($exp, {});
# $ast is now something like this:
# $ast = ['+',
#          2,
#         ['*',
#          ['$', 'a'],
#          4
#         ]
#        ];

Looks like it can handle exponentiations easily. So the AST in your case would be something like:

# $ast = ['^',
#         base,
#         exp
#        ];

You could build the desired expression 'Math.pow(base, exp)' by (recursively) reassemble a string from the 'base' and 'exp' subtrees.

If you want to implement a calculator in JavaScript then you need of course a JavaScript-Parser or you could rely on a server-backend implemented using Math::Expression::Evaluator.

Upvotes: 1

miku
miku

Reputation: 188164

You could use String.replace:

> s = "hello 2^3 pow!"
> s.replace(/(\d+)\^(\d+)/, "Math.pow($1, $2)")
"hello Math.pow(2, 3) pow!"

Upvotes: 3

Related Questions