Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 13 of 13
  1. #1
    Regular Coder
    Join Date
    Aug 2010
    Location
    Now Southern Oregon. I was born and had lived my life in Los Angeles until relocating last year (2010)
    Posts
    215
    Thanks
    52
    Thanked 1 Time in 1 Post

    convert string to executable code?

    I have a calculator program that takes a string entered into a text field,
    runs it through a syntax screening function and then executes the
    string via eval(), which I told I should never use.

    So the problem is how do I convert a string representing an arithmetic
    operation to executable code without using eval? (hopefully without
    another 50 -100 lines of code)

    as such
    Code:
    // screen code... assuming success..
    sample = '3*(42/9.8)'; // for instance
    return eval(sample) 
    // change to ????

  • #2
    Senior Coder xelawho's Avatar
    Join Date
    Nov 2010
    Posts
    2,981
    Thanks
    56
    Thanked 557 Times in 554 Posts
    I have no idea if this is more or less evil than the evil eval()...

    Code:
    <body>
    <input id="sums"/>
    <input type="button" value="calculate" onclick="calcIt()"/>
    <script type="text/javascript">
    function calcIt(){
    var sample = document.getElementById("sums").value;
    if(document.getElementById("myscript")){
    document.body.removeChild(document.getElementById("myscript"));
    }
    var scr=document.createElement("script");
    scr.id="myscript";
    scr.text='var myFunc=function(){return '+sample+'}';
    document.body.appendChild(scr);
    alert(myFunc())
    }
    </script>
    </body>

  • #3
    Regular Coder
    Join Date
    Mar 2006
    Posts
    728
    Thanks
    35
    Thanked 132 Times in 123 Posts
    Clean up the user input before eval-
    only allow integers, decimal points, parens and operators.

    And put down that scissors, you'll poke your eye out!

    Code:
    function calcuval(string){
    	try{
    		return eval(string.replace(/[^1-9.()/*+-]+/g, ''));
    	}
    	catch(er){
    		return NaN;
    	}
    }
    calcuval('3*(42/9.8)');>>> returned value: (Number)
    12.857142857142858
    */

  • Users who have thanked mrhoo for this post:

    jmrker (10-10-2012)

  • #4
    Regular Coder
    Join Date
    Aug 2010
    Location
    Now Southern Oregon. I was born and had lived my life in Los Angeles until relocating last year (2010)
    Posts
    215
    Thanks
    52
    Thanked 1 Time in 1 Post

    Yes, I am doing extensive screening.

    I have a function that actually crawls char for char through the string and detects all infractions to syntax rules I developed for this. (see below..
    I won't show the code that checks syntax)
    So, I take it so far that there is no 'safer', shorter way.
    All I can see is a bunch of code that will analyse the string and break into
    components and construct a function on the fly that will execute the calculation.

    Actually, I modified the program to allow spaces since this was written.

    This application only does arithmetic.

    1: Only one decimal point in a number.

    2: Only one operator in a row: +, -, /, *.

    3: Open parenthesis must be preceded immediately
    by an operator or another open parenthesis.

    4: For every open parenthesis there must be a closing parenthesis.
    First parenthesis must be an open parenthesis and the last must be
    a close parenthesis.
    For example 5*(9*8)) would give an imbalance parenthesis error
    where as 8*)+10 will give first parenthesis is not an open parenthesis

    5: Close parenthesis must be followed by an operator or
    another close parenthesis. 2*(2+9)(4/5) is an error.
    There must be an operator between (2+9) and (4/5)
    The one exeption is, of course, the last character in
    the expression can be a close parenthesis if it is
    need to balance an open parenthesis.

    6: Close parenthesis must be preceded by a number or closed
    parenthesis (preceded by a number)
    For example 4*(4-) would be an error

    7: When the expression begins with open parenthesis,
    precede it with the proper + or - sign.
    For example: (5-3)*(45+2); enter +(5-3)*(45+2)
    or -(5-3)*(45+2) if the sign for the first factor is negative

    8: Do not enter spaces anywhere.

    9: Do not enter empty parenthesis, with or without spaces: () or ( ).

    10: Any character other than digits (0 - 9), . (decimal point), + - * /, ( )
    is not allowed. * is for multiplication, / is for division.
    This includes $, or any money symbol, %, square root symbol, =,
    < (less than), > (greater than), ' or " for foot/inch or min/sec
    in angular measurements.

    Please note that 31/2 is read as 31 divided by 2, not 3 1/2.
    Convert fractions to decimals or express 3 1/2 as 3+(1/2);
    in context; 2*(3+(1/2)). 2*3.5 is cleaner.

    11: The last character cannot be an operator.

    12: If there is no fractional part of a factor, do not use a decimal point without trailing zero (0)

    Notes:
    The use of parenthesis can become confusing when used too much.
    Keeping track of open and close sets can be troublesome and give
    wrong results when not used correctly (even though no errors have
    occurred). In general use parenthesis to separate calculations
    to insure the proper order is maintained. In the example above;
    +(5-3)*(45+2), if the parenthesis where not used 3*45 would be
    done first, then 5-(3*45), then (5-(3*45)) - 2, which would be the
    wrong result. Like wise, in the example above, 2*(3+(1/2)), without
    the parenthesis, 2*3 and 1/2 would be done first, then (2*3)+(1/2).
    The first calculation gives 7, while the second gives 5.5 (without
    parenthetic isolation).

    In programming languages, the % (percent) sign is a valid operator.
    It is called modulus and will result in the fractional part of a division
    operation that does not result in a whole number.
    For instance: 5.5%1=.5
    It has some clever uses and I have used it successfully in programming
    logic. But it has little or no place in common arithmetic operations.

  • #5
    Senior Coder jmrker's Avatar
    Join Date
    Aug 2006
    Location
    FL
    Posts
    3,092
    Thanks
    38
    Thanked 498 Times in 492 Posts

    Question Replace function confusion (on my part)

    Quote Originally Posted by mrhoo View Post
    Clean up the user input before eval-
    only allow integers, decimal points, parens and operators.

    And put down that scissors, you'll poke your eye out!

    Code:
    function calcuval(string){
    	try{
    		return eval(string.replace(/[^1-9.()/*+-]+/g, ''));
    	}
    	catch(er){
    		return NaN;
    	}
    }
    calcuval('3*(42/9.8)');>>> returned value: (Number)
    12.857142857142858
    */
    @mrhoo
    Could you explain how that works?
    In particular the string.replace() argument.
    I thought it would replace any of the characters within the [brackets] with a space, but that is obviously not what it is doing.

    Is it replacing anything that is not within the [brackets] with a space? If yes, how or why?

    I thought I understood the .replace function, but this version seems to work backward from my understanding.


    Also, what is the (er) in the catch portion of the function? How might that be used or be of use elsewhere?
    Last edited by jmrker; 10-10-2012 at 04:17 AM.

  • #6
    Regular Coder
    Join Date
    Mar 2006
    Posts
    728
    Thanks
    35
    Thanked 132 Times in 123 Posts
    starting the replace regexp group with a caret ([^) negates the match, so anything not in the group is replaced with the empty string.


    The (er) is just a habit, I can't type a catch without it. Not required here.
    Last edited by mrhoo; 10-10-2012 at 04:57 AM.

  • #7
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    18,082
    Thanks
    203
    Thanked 2,542 Times in 2,520 Posts
    jmrker - you have interpreted '' as a space, not nothing. That is why I always use double quotes "" in preference.

    But my understanding is that eval is evil, not so much because it is slow, but because (as here) it allows the execution of arbitrary code (although here stripped to numbers and maths symbols). But perhaps that is not a risk with client-side Javascript running in the browser.

    For clarity I would do:-

    Code:
    try {
    string = string.replace(/[^1-9.()/*+-]+/g, "");  // clean up input
    return eval(string);  
    }
    Last edited by Philip M; 10-10-2012 at 08:31 AM.

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #8
    Senior Coder jmrker's Avatar
    Join Date
    Aug 2006
    Location
    FL
    Posts
    3,092
    Thanks
    38
    Thanked 498 Times in 492 Posts

    Thumbs up

    Quote Originally Posted by mrhoo View Post
    starting the replace regexp group with a caret ([^) negates the match, so anything not in the group is replaced with the empty string.


    The (er) is just a habit, I can't type a catch without it. Not required here.
    Thank you. That now makes sense.

    I was under the impression that the ^ character meant to start the replacement analysis from the beginning of the string. I thought also that you could start the analysis from the end of the string by using a $ character. Perhaps I am mixing other program language syntax again.

  • #9
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    18,082
    Thanks
    203
    Thanked 2,542 Times in 2,520 Posts
    The caret ^ has two meanings depending on the context.

    Within a pattern it means "the start of the string"

    Code:
    var str = "Philip";
    if (/^p/i.test(str)) {
    alert ("The first character of the string is a P");
    }
    But within a character class [square brackets] it means negation (not)

    Code:
    var str = "I have 3 sisters"
    if (/[^a-z\s]/gi.test(str)) {
    alert ("The string contains a character which is not a-z or space");
    }
    $ also has two meanings. One is, as you say, the end of the string. Also when using replace you can reference groups using ‘$1′, ‘$2′, ‘$3′ etc. in the replacement string.
    Code:
    var str  = "I wonder how I can remove (these brackets)..."
    str .replace(/\((.+?)\)/, '$1');  // Removes the brackets
    alert (str);
    https://developer.mozilla.org/en-US/...ar_Expressions
    Last edited by Philip M; 10-10-2012 at 04:18 PM.

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #10
    Senior Coder jmrker's Avatar
    Join Date
    Aug 2006
    Location
    FL
    Posts
    3,092
    Thanks
    38
    Thanked 498 Times in 492 Posts

    Thumbs up

    Quote Originally Posted by Philip M View Post
    The caret ^ has two meanings depending on the context.

    Within a pattern it means "the start of the string"

    Code:
    ...
    But within a character class [square brackets] it means negation (not)

    Code:
    ...
    https://developer.mozilla.org/en-US/...ar_Expressions
    Thanks. It was the second explanation I was missing from my limited knowledge base.

  • #11
    Regular Coder
    Join Date
    Aug 2010
    Location
    Now Southern Oregon. I was born and had lived my life in Los Angeles until relocating last year (2010)
    Posts
    215
    Thanks
    52
    Thanked 1 Time in 1 Post

    Actually, I avoid using regex as much as possible

    Well, I started a conversation... about use of regex. But all the replies still
    use eval. I have been avoiding regex as much as possible, in favor of
    string methods, as, assume the same is true for javascript as it is for php,
    that string functions/methods are much faster than regex.
    for instance:
    Code:
    // probably inside of a loop that looks at every char in a string
    var testChar = '?';
    if(('!@#$%^&*()_+').indexOf(testChar) > -1)
      {
        alert ('BOO...')
    }
    else
      {
     alert('Yay...')
    }

  • #12
    Senior Coder xelawho's Avatar
    Join Date
    Nov 2010
    Posts
    2,981
    Thanks
    56
    Thanked 557 Times in 554 Posts
    Quote Originally Posted by anotherJEK View Post
    But all the replies still use eval.
    are you sure about that?

  • #13
    Senior Coder jmrker's Avatar
    Join Date
    Aug 2006
    Location
    FL
    Posts
    3,092
    Thanks
    38
    Thanked 498 Times in 492 Posts

    Lightbulb

    Quote Originally Posted by anotherJEK View Post
    Well, I started a conversation... about use of regex. But all the replies still
    use eval. I have been avoiding regex as much as possible, in favor of
    string methods, as, assume the same is true for javascript as it is for php,
    that string functions/methods are much faster than regex.
    for instance:
    Unless you are in a multiple executed loop, I don't think the speed of a regex or eval() commands will make much difference to your outcome.

    I thought your original question was if there was a way to avoid using eval() without a ton of code for mathematical calculations. Probably not.

    The danger of using eval(), as I see it, is allowing users to execute non-math related code. To that end, the use of a regex comparison to filter out all but math related characters is probably safe.


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •