package
{
 public class MathParser
 {
  static public const RAD:int = 0;
  static public const DEG:int = 1;
  static public const GRAD:int = 2;
  
  static protected const _pi:Number = Math.PI;
  
  static public var instance:MathParser = new MathParser(1);
  
  
  protected var _val :Number;
  protected var _fac :Number;
  protected var _mode :int;
  protected var _rgxs :Array;
  protected var functionList:Array =
  ["abs", "acos", "asin", "atan", "ceil", "cos", "exp", "floor", "log", "sin", "sqrt", "tan"];
    
  public function MathParser( md:int )
  {
   mode  = md;
   _rgxs = new Array(10);
   _rgxs[0] = /[ \n\r\t]/g;
   _rgxs[1] = /(?<=[\d\)])(?=[a-df-z\(])|(?<=pi)(?=[^\+\-\*\/\\^!)])|(?<=\))(?=\d)|(?<=[^\/\*\+\-])(?=exp)/i;
   _rgxs[2] = /([a-z]*)\(([^\(\)]+)\)(\^|!?)/i;
   _rgxs[3] = /([a-z]{2,})([\+-]?\d+,*\d*[eE][\+-]*\d+|[\+-]?\d+,*\d*)/i;
   _rgxs[4] = /\{(.+)\}!" )/;
   _rgxs[5] = /([\d.]+,*[\d.]*[eE][\+-]?[\d.]+|[\d.]+,*[\d.]*)!/;
   _rgxs[6] = /\{(.+)\}\^(-?[\d.]+,*[\d.]*[eE][\+-]?[\d.]+|-?[\d.]+,*[\d.]*)/;
   _rgxs[7] = /([\d.]+,*[\d.]*e[\+-]?[\d.]+|[\d.]+,*[\d.]*)\^(-?[\d.]+,*[\d.]*[eE][\+-]?[\d.]+|-?[\d.]+,*[\d.]*)/;
   _rgxs[8] = /([\+-]?[\d.]+,*[\d.]*[eE][\+-]?[\d.]+|[\-\+]?[\d.]+,*[\d.]*)([\/\*])(-?[\d.]+,*[\d.]*[eE][\+-]?[\d.]+|-?[\d.]+,*[\d.]*)/;
   _rgxs[9] = /([\+-]?[\d.]+,*[\d.]*[eE][\+-]?[\d.]+|[\+-]?[\d.]+,*[\d.]*)([\+-])(-?[\d.]+,*[\d.]*[eE][\+-]?[\d.]+|-?[\d.]+,*)[\d.]*/;
  }
  // Getter & Setter
  public function get Result():Number { return _val; }
  public function get mode():int { return _mode; }
  public function set mode(n:int):void
  {
   _mode = n;
   switch( n )
   {
    case RAD : _fac = 1.0; break;
    case DEG : _fac = 2.0 * _pi / 360.0; break;
    case GRAD: _fac = 2.0 * _pi / 400.0; break;
   }
  }
  
  public function parseFormula( str:String ):Number
  {
   try
   {
    var ss = str.replace(/[  \n\r\t]/g, " ");
    //replace all constants
    
    ss = ss.replace(/PI/g, Math.PI.toString());
    ss = ss.replace(/E/g, Math.E.toString());
    ss = ss.replace(/LN2/g, Math.LN2.toString());
    ss = ss.replace(/LN10/g, Math.LN10.toString());
    ss = ss.replace(/LOG2E/g, Math.LOG2E.toString());
    ss = ss.replace(/LOG10E/g, Math.LOG10E.toString());
    ss = ss.replace(/SQRT1_2/g, Math.SQRT1_2.toString());
    ss = ss.replace(/SQRT2/g, Math.SQRT2.toString());
    
    //remove blank spaces
    ss = ss.replace( _rgxs[0], "" );
    
    // remove others
    
    ss = ss.replace(_rgxs[1],"*");
    ss = ss.replace("pi", Math.PI.toString());
    
    var o:Object = _rgxs[2].exec( ss );
    
    while( o != null )
    {
     if( o[3].length > 0 )
     {
      ss = ss.replace( o[0], "{" + o[1] + evalString( o[2] ) + "}" + o[3] );
     }
     else
     {
      ss = ss.replace( o[0], o[1] + evalString( o[2] ) );
     }
     o = _rgxs[2].exec( ss );
    }   
    
    _val = Number( evalString( ss ) );
    return _val;
   }
   catch (e:Error)
   {
    trace(e);
    return NaN;
   }
   return NaN;
  }
  
  protected function evalString( ss:String ):String
  {
   //trace(ss);
   var oo:Object = _rgxs[3].exec( ss );
   
   while( oo != null && functionList.indexOf(oo[1].toLowerCase() ) > -1  )
   {
    switch( oo[1].toLowerCase() )
    {
     case "abs" : ss = ss.replace( oo[0], Math.abs( Number( oo[2] ) ).toString() ); break;
     case "acos" : ss = ss.replace( oo[0], Math.acos( _fac * Number( oo[2] ) ).toString() ); break;
     case "asin" : ss = ss.replace( oo[0], Math.asin( _fac * Number( oo[2] ) ).toString() ); break;
     case "atan" : ss = ss.replace( oo[0], Math.atan( _fac * Number( oo[2] ) ).toString() ); break;
     case "cos" : ss = ss.replace( oo[0], Math.cos( _fac * Number( oo[2] ) ).toString() ); break;
     case "ceil" : ss = ss.replace( oo[0], Math.ceil( Number( oo[2] ) ).toString() ); break;
     case "exp"  : ss = ss.replace( oo[0], Math.exp( Number( oo[2] ) ).toString() ); break;
     case "floor": ss = ss.replace( oo[0], Math.floor( Number( oo[2] ) ).toString() ); break;
     case "log" : ss = ss.replace( oo[0], Math.log( Number( oo[2] ) ).toString() ); break;
     case "sin" : ss = ss.replace( oo[0], Math.sin( _fac * Number( oo[2] ) ).toString() ); break;
     case "sqrt" : ss = ss.replace( oo[0], Math.sqrt( Number( oo[2] ) ).toString() ); break;
     case "tan" : ss = ss.replace( oo[0], Math.tan( _fac * Number( oo[2] ) ).toString() ); break;
    }
    oo = _rgxs[3].exec( ss );
   }
   
   // {5}!
   var n:Number;
   oo = _rgxs[4].exec( ss );
   while( oo != null )
   {
    n = Number( oo[1] );
    if( (n < 0) && (n != Math.round(n)) ){trace("ERROR........");}
    ss = ss.replace( _rgxs[4], checkNumber( Number( oo[1] ) ).toString() );
    oo = _rgxs[4].exec( ss );
   }
   
   // 5!
   oo = _rgxs[5].exec( ss );
   while( oo != null )
   {
    n = Number( oo[1] );
    if( (n < 0) && (n != Math.round(n)) ){trace("ERROR........");}
    ss = ss.replace( _rgxs[5], checkNumber( Number( oo[1] ) ).toString() );
    oo = _rgxs[5].exec( ss );
   }
   
   // {-2}^-1
   oo = _rgxs[6].exec( ss );
   
   while( oo != null )
   {
    ss = ss.replace( oo[0], Math.pow( Number( oo[1] ), Number( oo[2] ) ).toString() );
    oo = _rgxs[6].exec( ss );
   }
   
   // 2^-1
   oo = _rgxs[7].exec( ss );
   while( oo != null )
   {
    ss = ss.replace( _rgxs[7], Math.pow( Number( oo[1] ), Number( oo[2] ) ).toString() );
    oo = _rgxs[7].exec( ss );
   }
   
   oo = _rgxs[8].exec( ss );
   
   var ret:Number;
   while( oo != null )
   {
    if (oo[2] == "*")
    {
     ret = Number( oo[1] ) * Number( oo[3] );
     if( (ret < 0) || (oo.index == 0) ) ss = ss.replace( _rgxs[8], ret.toString() );
     else ss = ss.replace( oo[0], "+" + ret );
    }
    else if (oo[2] == "/")
    {
     ret = Number( oo[1] ) / Number( oo[3] );
     if( (ret < 0) || (oo.index == 0) ) ss = ss.replace( _rgxs[8], ret.toString() );
     else ss = ss.replace( _rgxs[8], "+" + ret );
    }
    oo = _rgxs[8].exec( ss );
   }
   
   oo = _rgxs[9].exec( ss );
   while( oo != null )
   {
    if (oo[2] == "+")
    {
     ret = Number( oo[1] ) + Number( oo[3] );
     if( (ret < 0) || (oo.index == 0) ) ss = ss.replace( _rgxs[9], ret.toString() );
     else ss = ss.replace( _rgxs[9], "+" + ret );
    }
    else if (oo[2] == "-")
    {
     ret = Number( oo[1] ) - Number( oo[3] );
     if( (ret < 0) || (oo.index == 0) ) ss = ss.replace( _rgxs[9], ret.toString() );
     else ss = ss.replace( _rgxs[9], "+" + ret );
    }
    oo = _rgxs[9].exec( ss );
   }
   
   if( ss.substr(0,2) == "--" ) ss = ss.substr(2);
   
   return ss;
  }
  
  protected function checkNumber( n:Number ):Number
  {
   return (n == 0.0) ? 1.0 : (n * checkNumber( n - 1.0 ));
  }
 }
}
Langganan:
Posting Komentar (Atom)
Note: (regards to the original founder)
BalasHapusThe idea is not originally mine. I have watch at past (in a dMicrosoft dot net application) but not accurate enought but the idea always in my brain. So I remake it in AS3. And this one is accurate.