美文网首页iOS Developer
HMExpressionEvaluator 一个使用简单又强大的

HMExpressionEvaluator 一个使用简单又强大的

作者: Dean_F | 来源:发表于2017-06-12 20:39 被阅读118次

    demo下载地址

    一. 简介

    1. 一个数学表达式计算器,能实现和 UIWebView 的 stringByEvaluatingJavaScriptFromString: 一样的计算效果,但效率要高很多,可以在子线程中执行;

    2. 基本全面覆盖 NSExpression 的 expressionForFunction:arguments 中的所有function,使用要比 NSExpression 简单很多,只需将注意力放大expression表达式的编辑上,将任意复杂度的表达式,通过eval:方法传入便可轻松得到计算结果;

    3. 支持复杂加减乘除四则运算,与或非逻辑运算,和大于小于等比较运算;

    4. 支持三目运算;

    5. 表达式中能自动识别处理的函数,基本全部覆盖NSExpression,有的未实现的,因为可以自己有数学表达式表达,比如 a+b,这个表达式计算最基本功能,无需通过函数调用来实现;

    6. 以上所述的计算类型在符合数学表达式逻辑的前提下,可以组合在一个表达式中,函数支持嵌套调用;

    7. 支持字符串相加(字符串拼接);

    8. 开发者可以扩展自己的函数,通过构建 HMExpressionFunction 对象来声明自定义的函数,详细使用方式可以参考 demo。

    二. 使用方式

    1. 引入头文件

      #import"HMExpressionEvaluator.h"
      

      HMExpressionEvaluator.h 文件中只声明了4个方法:

      • -(id)eval:(NSString *)expression // 用于传入表达式进行计算并返回计算结果
      • -(void)setCustomFunctions:(NSDictionary *)customFunctions // 用于给开发者注册自定义方法
      • -(void)setDateFormatter:(NSDateFormatter *)dateFormatter // 设置支持的日期格式,默认只支持 yyyy-MM-dd HH:mm:ss 格式
      • -(void)withoutFunctionTransfer:(BOOL)withoutFunction; // 不支持函数调用,仅用于计算纯数学表达式,默认为支持函数调用

    开发者仅需通过这4个 API 来使用表达式计算全部功能

    ```Objective-C
    // HMExpressionEvaluator.h

    @interface HMExpressionEvaluator : NSObject
    
    #pragma mark - API
    /**
     *  表达式计算
     *
     *  @param expression 需要计算的表达式
     *
     *  @return 计算结果
     */
    - (id)eval:(NSString *)expression;
    
    /**
     *  设置开发者自定义的函数集
     *
     *  @param customFunctions 每个函数用 HMExpressionCustomFunction 对象来描述,以函数名为 key
     *                         
     */
    - (void)setCustomFunctions:(NSDictionary *)customFunctions;
    
    /**
     *  设置支持的日期格式,默认只支持 yyyy-MM-dd HH:mm:ss 格式
     *
     *  @param dateFormat 日期格式
     */
    - (void)setDateFormat:(NSString *)dateFormat;
    
    /**
     *  不支持函数调用,仅用于计算纯数学表达式,默认为支持函数调用
     */
    - (void)withoutFunctionTransfer:(BOOL)withoutFunction;
    
    @end
    ```
    
    1. 具体使用方式

      1. 支持的数学运算操作符和操作数类型

        typedef NS_ENUM(NSInteger, HMExpressionNodeType)
        {
            /**
             * 未知  0
             */
            Unknown,  
              
            /**
             * + 加
             */
            Plus,
            
            /**
             * - 减
             */
            Subtract,
            
            /**
             * * 乘
             */
            MultiPly,
            
            /**
             * / 除
             */
            Divide,
            
            /**
             * ( 左括号
             */
            LParentheses,
            
            /**
             * ) 右括号
             */
            RParentheses,
            
            /**
             * % 求模,取余
             */
            Mod,
            
            /**
             * ^ 幂运算
             */
            Power,
            
            /**
             * << 左移位
             */
            LShift,
            
            /**
             * >> 右移位
             */
            RShift,
            
            /**
             * & 按位与
             */
            BitwiseAnd,
            
            /**
             * | 按位或
             */
            BitwiseOr,
            
            /**
             * && 逻辑与
             */
            And,
            
            /**
             * || 逻辑或
             */
            Or,
            
            /**
             * ! 逻辑非
             */
            Not,
            
            /**
             * == 比较等
             */
            Equal,
            
            /**
             * != 或 <> 比较不等
             */
            Unequal,
            
            /**
             * > 比较大于
             */
            GT,
            
            /**
             * < 比较小于
             */
            LT,
            
            /**
             * >= 比较大于等于
             */
            GTOrEqual,
            
            /**
             * <= 比较小于等于
             */
            LTOrEqual,
            
            /**
             * 数值
             */
            Numeric,
            
            /**
             * 字符串
             */
            String,
            
            /**
             * 日期时间
             */
            Datetime
        };
        
      2. 使用示例

        // 简单四则运算
        [HMExpressionEvaluator eval:@"22 + 33 * 66 + 3^5"]; // 3^5 3的5次方
        
        // 简单比较运算
        [HMExpressionEvaluator eval:@"5 < 6"];
        
        // 逻辑运算
        [HMExpressionEvaluator eval:@"5 < 3 || 6 > 5)"];
        
        // 位运算
        [HMExpressionEvaluator eval:@"4 << 5"];
        
        // 字符串相加
        [HMExpressionEvaluator eval:@"\"Hello\" + \" \" + \"World\" << 5"];
        
      3. 包含函数的运算

        1. 支持的函数清单

          // 逻辑运算类
          ternaryOperation(5<7, \"真\", \"假\") // 三目表达式
          
          日期类处理方法, 日期字符串格式要求为:yyyy-MM-dd或者yyyy-MM-dd HH:mm:ss
          dateDiff(差值类型, 较早日期, 较晚日期) // 时间差值
          getYear(date) // 获取日期中的年份
          getQuarter(date) // 获取日期中的第几季度
          getLocalQuarter(date) // 获取日期中的中文第几季度
          getMonth(date) // 获取日期中的月份
          getLocalMonth(date) // 获取日期中的中文月份
          getWeek(date) // 获取日期中的第几周
          getLocalWeek(date) // 获取日期中的中文第几周
          getDayOfWeek(date) // 获取日期中的星期几
          getLocalDayOfWeek(date) // 获取日期中的中文星期几
          getDay(date) // 获取日子
          getLocalDay // 获取中文日子
          now() // 获取现在时间
          
          // 数值类
          getLocalMoney(digit) // 将数值转换为大写金额
          round(digit) // 数值四舍五入
          ceil(digit) // 数值0舍1入
          trunc(digit) // 向下取整
          floor(digit) // 向下取整
          abs(digit) // 求绝对值
          sqrt(digit) // 开平方
          log(digit) // 底数为e对数
          ln(digit) // 底数为e对数
          log10(digit) // 底数为10对数
          log2(digit) // 底数为2对数
          raiseToPower(x, n) // 计算 x 的 n 次方
          exp(digit) // 求e的x次方
          bitwiseXor(a, b) // a 异或 b
          onesComplement(a) // a 的补码
          average(digit, digit, ...) // 求平均
          sum(digit, digit, ...) // 求和
          count(digit, digit, ...) // 计数
          min(digit, digit, ...) // 找最小值
          max(digit, digit, ...) // 找最大值
          median(digit, digit, ...) // 找中值
          mode(digit, digit, ...) // 一数组或数据区域中出现频率最多的数值
          stddev(digit, digit, ...) // 样本标准偏差
          random(void) // 获取随机数小数
          randomn(digit) // 获取随机数整数
          
          // 字符串类
          contains("待检字符串", "被包含字符串") // 检查包含子字符串
          unContains("待检字符串", "不被包含字符串") // 检查不包含子字符串
          lowercase("字符串") // 转小写
          uppercase("字符串") // 转大写
          
        2. 调用方式

          // 三目运算函数
          [HMExpressionEvaluator eval:@"ternaryOperation(5<7, \"真\", \"假\")"];
          
          // 获取大写金额
          [HMExpressionEvaluator eval:@"getLocalMoney(10086)"];
          
          // 复杂混合运算表达式
          [HMExpressionEvaluator eval:@"dateDiff(\"dd\", \"2016-12-17\", now()) * 10 - getYear(now()) + max(11, 22,33,1000) * sqrt(floor(1000.445))"];
          
        3. 自定义函数的使用,以 demo 为例:


          第一步:自定义方法的OC实现


          demo 中在 ViewController.m 实现了如下四个方法,可以看到返回时,均构建了 HMExpressionCustomFunctionResult 类实例来返回,这是必须的;

          方法中传入的 param 会根据表达式中调用函数时括号内传入的参数情况解析成字符串,一维数组,或者二维数组,具体规则看如下代码段的注释。

          #pragma mark - 自定义函数测试
          /*
           *  不带参函数
           *  在表达式中写入 test1()
           *
           *  @return 创建 HMExpressionFunctionResult 实例,返回函数运行结果
           */
          - (HMExpressionCustomFunctionResult *)test1
          {
              return [[HMExpressionCustomFunctionResult alloc] initWithResult:@"测试不带参函数"
                                                               dataType:HMExpressionCustomFunctionResultDataTypeString] ;
          }
          
          /*
           *  带一个加单参数的函数
           *
           *  @param param 如在表达式中写:test2(123) 则此处 param 为: @"123"
           *
           *  @return 创建 HMExpressionFunctionResult 实例,返回函数运行结果
           */
          - (HMExpressionCustomFunctionResult *)test2:(id)param
          {
              return [[HMExpressionCustomFunctionResult alloc] initWithResult:[NSString stringWithFormat:@"测试带参函数,传入参数为:%@", param]
                                                               dataType:HMExpressionCustomFunctionResultDataTypeString];
          }
          
          /*
           *  一维多参函数,将所有参数拼接成一个字符串
           *  如表达式中写:test3(123, 456, 789...) 数量根据自己的需要来定
           *
           *  @param param 此处得到 param 为一维数组 @[@"123", @"456", @"789"...]
           *
           *  @return 创建 HMExpressionFunctionResult 实例,返回函数运行结果
           */
          - (HMExpressionCustomFunctionResult *)test3:(id)param
          {
              // 将所有参数拼接成一个字符串
              
              NSMutableString *result = [NSMutableString string];
              for(NSString *str in param)
              {
                  [result appendString:str];
              }
              
              return [[HMExpressionCustomFunctionResult alloc] initWithResult:result
                                                               dataType:HMExpressionCustomFunctionResultDataTypeString];
          }
          
          /*
           *  二维多参函数,函数功能为将所有参数拼接为字符串
           *  如表达式中写:test3(123, [456, 789], @"333", [234]...) 数量根据自己的需要来定
           *
           *  @param param 此处得到 param 为二维数组 @[@"123", @[@"456", @"789"], @"333", @[@"234"]...]
           *
           *  @return 创建 HMExpressionFunctionResult 实例,返回函数运行结果
           */
          - (HMExpressionCustomFunctionResult *)test4:(id)param
          {
              NSMutableString *result = [NSMutableString string];
              
              for(id obj in param)
              {
                  if([obj isKindOfClass:[NSArray class]])
                  {
                      for(NSString *str in (NSArray *)obj)
                      {
                          [result appendString:str];
                      }
                  }
                  else
                  {
                      [result appendString:obj];
                  }
              }
              
              return [[HMExpressionCustomFunctionResult alloc] initWithResult:result
                                                               dataType:HMExpressionCustomFunctionResultDataTypeString];
          }
          

          第二步:构建 HMExpressionCustomFunction 实例


          如下代码将上述四个 test 方法分别构建一个 HMExpressionCustomFunction 实例来进行描述,并以用于表达式调用的函数名为 key 存入字典,准备注入表达式解析计算器中。

          - (NSDictionary *)customFunctions
          {
              if(!_customFunctions)
              {
                  _customFunctions = [NSMutableDictionary dictionary];
                  // test1 无参函数
                  HMExpressionCustomFunction *function = [[HMExpressionCustomFunction alloc] initWithFunctionName:@"test1"
                                                                                                                   selector:@selector(test1)
                                                                                                                     target:self];
                  [_customFunctions setObject:function forKey:function.functionName];
                  // test2 带一个参数的函数
                  function = [[HMExpressionCustomFunction alloc] initWithFunctionName:@"test2"
                                                                                  selector:@selector(test2:)
                                                                                    target:self];
                  [_customFunctions setObject:function forKey:function.functionName];
                  // test3 带多个一维参数的函数
                  function = [[HMExpressionCustomFunction alloc] initWithFunctionName:@"test3"
                                                                                  selector:@selector(test3:)
                                                                                    target:self];
                  [_customFunctions setObject:function forKey:function.functionName];
                  // test4 带多个二维参数的函数
                  function = [[HMExpressionCustomFunction alloc] initWithFunctionName:@"test4"
                                                                                  selector:@selector(test4:)
                                                                                    target:self];
                  [_customFunctions setObject:function forKey:function.functionName];
              }
              return _customFunctions;
          }
          

          第三步:将构建好的 HMExpressionCustomFunction 实例注入表达式解析计算器


          代码如下,即在 demo 中点击 “计算” 按钮时执行的代码

          /*
           *  创建表达式计算器对象
           */
          - (HMExpressionEvaluator *)evaluator
          {
              if(!_evaluator)
              {
                  _evaluator = [[HMExpressionEvaluator alloc] init];
                  [_evaluator setCustomFunctions:self.customFunctions]; // 注入自定义函数集
                  
                   // 默认就是这个格式
                   // [_evaluator setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
                  
                   // 默认就是 false,即表达式支持函数调用,当表达式不需要函数调用是,调用该方法置为 true,可以调高运算效率
                   // [_evaluator withoutFunctionTransfer:false];
              }
              return _evaluator;
          }
          

    最后上图看看运行效果

    1. 开始运行.png 2. 选择函数.png 3. 选择指定测试用例.png 4. 选择确定输入到了输入框.png 5. 表达式无误完成计算.png 6. 表达式有错误计算失败.png



    感兴趣请下载demo研究,运行后,点击快速测试,快速一睹 HMExpressionValuator 的风采吧!

    意见建议请联系:

    QQ: 247159603
    **博客:猿视界

    相关文章

      网友评论

        本文标题:HMExpressionEvaluator 一个使用简单又强大的

        本文链接:https://www.haomeiwen.com/subject/wicrqxtx.html