Advanced Search

Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: Need help converting string to formula

  1. #1
    Join Date
    Sep 2008
    Posts
    119
    Thanks
    13
    Thanked 0 Times in 0 Posts

    Default Need help converting string to formula

    Ok, so I have a page where I can input mathematical formulas -

    ie: a text input with the value = "(((3+5)*8)/1.4)".

    What I am trying to do is convert that string to an actual answer.

    Given, in javascript I can write out the equation internally, but how to convert a string to utilize javascripts internal functionality?

    I realize I could assign variables to each mathematical character and split those chars in a string length -

    r = );

    but isn't there an easier way?

    any help much appreciated.

    - Ben

  2. #2
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,878
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    You've found one of the few places in which use of eval() is justified. Just check for unwanted characters first:

    Code:
    var Calculator = (function() {
      function safe(expr) {
        if (/[^\d*-+\/()^%. ]/.test(expr))
          throw new Exception("Malformed expression.");
    
        return expr;
      }
    
      function calculate(expr) {
        try {
          return eval(safe(expr));
        } catch (e) {
          alert("Malformed expression.");
        }
      }
    
      return { calculate: calculate };
    })();
    Last edited by Twey; 02-16-2009 at 04:03 PM. Reason: Fix regex.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends franšais | entiendo espa˝ol | t˘i Ýt hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  3. The Following User Says Thank You to Twey For This Useful Post:

    Falkon303 (02-16-2009)

  4. #3
    Join Date
    Sep 2008
    Posts
    119
    Thanks
    13
    Thanked 0 Times in 0 Posts

    Default

    You sir, are a gentleman and a scholar! Thanks much!

  5. #4
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    28,708
    Thanks
    43
    Thanked 3,133 Times in 3,097 Posts
    Blog Entries
    12

    Default

    I believe your test:

    Code:
    if (/^[0-9*-+\/()^%]/.test(expr))
    should be:

    Code:
    if (/[^(-9 ]|,|([\d ]\.\d+\.)|(\D\.\D)/.test(expr))
    And the whole thing is overly complex:

    Code:
    var Calculator = {
      safe: function(expr) {
        if (/[^(-9 ]|,|([\d ]\.\d+\.)|(\D\.\D)/.test(expr))
          alert("Malformed expression.");
        else
          return expr;
        return undefined;
      },
      calculate: function(expr) {
        return eval(this.safe(expr));
      }
    };
    Last edited by jscheuer1; 02-16-2009 at 08:53 AM. Reason: add revised object definition
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  6. #5
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,878
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    I believe your test:
    Code:
    if (/^[0-9*-+\/()^%]/.test(expr))
    should be:
    Code:
    if (/[^(-9 ]|,|([\d ]\.\d+\.)|(\D\.\D)/.test(expr))
    And the whole thing is overly complex:
    I think you missed the point a little. safe() is just for checking that there aren't any weird function calls in the expression (although I did mean [^ and not ^[, I really do need the decimal point in there, and \d is nicer than 0-9). We catch any otherwise-malformed or impossible calculations later, in the catch block; safe() throws an exception to unify the error handling there.

    You can save three lines by doing it your way, but at the cost of names and precompilation, exposing safe() which the user doesn't really need to know about, and requiring the context to be the global object, which makes it awkward to use as a first-class function. I'd rather stick with the original.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends franšais | entiendo espa˝ol | t˘i Ýt hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  7. #6
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    28,708
    Thanks
    43
    Thanked 3,133 Times in 3,097 Posts
    Blog Entries
    12

    Default

    Hmm. Let's see:

    Code:
    [^(-9 ]|,
    or what as an alternative? The above takes in:

    ()*+-./0123456789

    and space as the 'allowed' (via negativa) characters.

    I don't quite get the bit about exposure, safe() is accessible (in my version), but not really exposed, it can only be accessed through the already exposed object, which is exposed in both our versions.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  8. #7
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,878
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    It does, although I think the intention is somewhat less clear. I was talking more about the rest of the pattern, where you do further regex validation, and the removal of the try/catch block, whereby you fail to catch patterns that contain only valid characters but are nevertheless not valid for whatever reason.

    I don't quite get the bit about exposure, safe() is accessible (in my version), but not really exposed, it can only be accessed through the already exposed object, which is exposed in both our versions.
    In programming terms, we refer to something accessible to the user as 'exposed' (or 'public'). This isn't a big deal in JS, since neither the language nor its philosophy really encourage it, but encapsulating methods that don't need to be exposed means one can rely on the fact that they're never going to be used by users of your code, and therefore feel free to change the internal implementation as desired, while a public API should generally remain stable for fear of breaking existing code. In our code, safe() is an implementation detail: it may be replaced, and it's not designed to be used by external code — the fact that the check is incomplete makes it pretty much worthless for any usage except our own, which later does more extensive checking at evaluation-time by means of the try/catch block. If we had a more reliable version of safe() then it might be worthwhile exposing part of it as a boolean isSafe() or something, but I think that evaluating the code twice in order to perform validation would be clumsy in the extreme. If we did desire more flexibility, we would remove the try/catch block and allow the calling code to handle any exceptions that might occur.
    Last edited by Twey; 03-15-2009 at 08:09 PM.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends franšais | entiendo espa˝ol | t˘i Ýt hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  9. #8
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    28,708
    Thanks
    43
    Thanked 3,133 Times in 3,097 Posts
    Blog Entries
    12

    Default

    OK, then:

    Code:
    var Calculator = (function(){
      var safe = function(expr){
        if (/[^(-9 ]|,/.test(expr))
          throw('');
          return expr;
      };
      return {calculate: function(expr){
        try {
         return eval(safe(expr));
        } catch(e){alert("Malformed expression.");}
       }
      };
    })();
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  10. #9
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,878
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    That's nice, although you're still losing precompilation and names, and if you put the formatting back* it's the same size as mine

    *
    Code:
    var Calculator = (function() {            var Calculator = (function() {
      var safe = function(expr) {               function safe(expr) {
        if (/[^(-9 ]|,/.test(expr))               if (/[^\d*-+\/()^%. ]/.test(expr))
          throw('');                                throw "Malformed expression.";
    
        return expr;                              return expr;
      };                                        } 
    
      return {                                  function calculate(expr) {
        calculate: function(expr) {               try {
          try {                                     return eval(safe(expr));
            return eval(safe(expr));              } catch (e) {
          } catch (e) {                             alert("Malformed expression.");
            alert("Malformed expression.");       }
          }                                     } 
        }
      };                                        return { calculate: calculate };
    })();                                     })();
    Last edited by Twey; 02-16-2009 at 07:41 PM.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends franšais | entiendo espa˝ol | t˘i Ýt hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  11. #10
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    28,708
    Thanks
    43
    Thanked 3,133 Times in 3,097 Posts
    Blog Entries
    12

    Default

    I'm not sure what you mean by precompilation or names. By the time Calculator.calculate() is used, it is compiled. What names are available in your version that aren't available in mine?

    Of course, I could be missing something. This is the first time I think I really understood public and private, so I'm certainly not opposed to learning more.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

Bookmarks

Posting Permissions

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