2

I'm trying to get an exact match from a given string, and then manipulate that string. I have a rather large calculator program that you can see here: http://www.marcusparsons.com/projects/calculator. There's nothing on the main pages just yet, and the original code is quite long.

The goal has been to implement a feature into the calculator where Math doesn't have to be prefixed to Math objects/methods. It's worked great up until I added a function that allows a user to use the "acosh()" method (and experimental methods) regardless of whether it's implemented in their browser or not (ehem...IE). The problem I run into is that the algorithm I have now wants to replace "acosh" with aMath.cosh()" because it sees "cos" inside of "acosh".

So, when I pass it the string "acosh(1)+cos(pi/3)" it turns into "aMath.cosh(1)+cos(Math.PI/3)".

Edit: The string above should be "acosh(1)+Math.cos(Math.PI/3)".

I'm a newbie at Regular Expressions, and I'm thinking that is where my problem is.

Here's the example code: http://jsfiddle.net/mparson8/2ej5n3u4/4/

var $mathKeywords = ["E", "LN2", "LN10", "LOG2E", "LOG10E", "PI", "SQRT1_2", "SQRT2", "abs", "acos", "asin", "asinh", "atan", "atan2", "atanh", "cbrt", "ceil", "clz32", "cos", "exp", "expm1", "floor", "fround", "hypot", "imul", "log1p", "log10", "log2", "max", "min", "pow", "random", "round", "sin", "sinh", "sqrt", "tan", "tanh", "trunc"];

var $resultVal = "acosh(1)+cos(PI/3)".toLowerCase();
try {
//Iterate over each Math object/method
$.each($mathKeywords, function (i, val) {
    //Convert val within array to a lower case form
    var $lowerKey = val.toLowerCase();
    //The regex pattern I came up with
    var pattern = new RegExp("(^|\\W)" + $lowerKey + "($|\\W)");
    //See if pattern gives a match within $resultVal
    var $location = $resultVal.match(pattern);
    //Math keyword is found
    if ($location != null) {
        //replace the lowercase version of the math keyword with its properly cased version prepended 
        //with Math. i.e. cos becomes Math.cos and pi becomes Math.PI
        $resultVal = $resultVal.replace($lowerKey, "Math." + val);
    }
});
//Set the result element's value to an evaluation of $resultVal
//A better implementation of the eval exists within the calc program
alert($resultVal);
alert(eval($resultVal));
} catch (err) {
alert("Error: Cannot process expression due to " + err + ".");
}

I appreciate any and all help! :)

6
  • where is acosh in your list? Commented Feb 18, 2015 at 23:53
  • (^|\W)cos($|\W) does not match acosh; you've correctly added word boundaries, so I'm not sure that's your problem... Commented Feb 18, 2015 at 23:55
  • acosh does not belong in the list, because then it would be a part of the Math prototype, and if you try to run "acosh" in IE, you will get an error because it doesn't exist as part of the Math methods. I haven't taken the other experimental methods out yet, because I have just been running tests. Commented Feb 19, 2015 at 0:06
  • Mark, that regular expression is not the same as the one that is returned from the code. If you show an alert for the $location after it's been set $resultVal.match(pattern); you'll see that it returns some extra characters, as well. Commented Feb 19, 2015 at 0:08
  • 1
    @MarcusParsons Oh... that's because the \W is matching the punctuation/operators (e.g. regex101.com/r/zH9hH1/1). What you want is a zero-width assertion, or a capturing group. Just replace (^|\\W) and ($|\\W) both with \b (or \\b in the string) e.g. regex101.com/r/pP9pT0/1 Commented Feb 19, 2015 at 0:11

1 Answer 1

5

If you want to continue on the path of regular expressions, this seems to work:

var $mathKeywords = ["E", "LN2", "LN10", "LOG2E", "LOG10E", "PI", "SQRT1_2", "SQRT2", "abs", "acos", "asin", "asinh", "atan", "atan2", "atanh", "cbrt", "ceil", "clz32", "cos", "exp", "expm1", "floor", "fround", "hypot", "imul", "log1p", "log10", "log2", "max", "min", "pow", "random", "round", "sin", "sinh", "sqrt", "tan", "tanh", "trunc"];

var $resultVal = "acosh(1)+cos(PI/3)".toLowerCase();
try {
    //Iterate over each Math object/method
    $.each($mathKeywords, function (i, val) {
        //Convert val within array to a lower case form
        var $lowerKey = val.toLowerCase();
        var pattern = new RegExp("\\b" + $lowerKey + "\\b", "g");
        //See if pattern gives a match within $resultVal
        var $location = $resultVal.match(pattern);
        //Math keyword is found
        if ($location != null) {
            //replace the lowercase version of the math keyword with its properly cased version prepended 
            //with Math. i.e. cos becomes Math.cos and pi becomes Math.PI
            $resultVal = $resultVal.replace(pattern, "Math." + val);
        }
    });
    //Set the result element's value to an evaluation of $resultVal
    //A better implementation of the eval exists within the calc program
    console.log($resultVal);
    console.log(eval($resultVal));
} catch (err) {
    alert("Error: Cannot process expression due to " + err + ".");
}

Output:

acosh(1)+Math.cos(Math.PI/3)

(actually its Error: Cannot process expression due to ReferenceError: acosh is not defined. but you get the point)


Changes:

  • Use \b as a word boundary
  • Use pattern (with word boundary) in replacement
  • Use g flag to replace all occurrences.
Sign up to request clarification or add additional context in comments.

5 Comments

no. you will still have hte problem I described above.
Rearrange the list and I think we might have a winner
@deweyredman Your are not correct. The word boundary \b takes care of that. \bcos\b will not match .acos (or .acosh).
Halcyon, that was exactly what I needed. My problem was BOTH the regular expression and what I needed replacing. I feel like it's a Duh! moment. Thank you a ton! :)
This is really a very good answer. This line needs to be highlighted: new RegExp("\\b" + $lowerKey + "\\b", "g");

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.