任务:
我计划解析 NSPredicate 中的公式字符串,并用其数值替换字符串中的变量。这些变量是我的数据模型中现有对象实例的属性的名称,例如我有一个类“company”,其实例为“Apple Corp.”。
设置:
我的公式如下所示:“Profitability_2011_in% = [2011 年利润]/[2011 年收入]”
实例“Apple Corp”将具有以下属性:
2009 年收入 = 10,2010 年收入 = 20,2011 年收入 = 30, 2009 年利润 = 5,2010 年利润 = 10,2011 年利润 = 20。
因此,该公式将得出 20/30 = 67%。
变量通常是二维的,例如由财务报表项目的“利润”和“年份”(例如 2011 年)定义。 变量包含在 [ ] 中,维度由“”(空格)分隔。
我会怎么做
我的实现将从 NSRegularExpression 的 matchesInString:options:range:
开始,获取公式中所有变量的数组(Profit 2011、Revenue 2011),然后构造一个 NSDictionary(key = 变量名称)通过查询我的数据模型从该数组中取出。
你觉得怎么样?
- 您认为有更好的方法吗?
- 在公式中,如何用变量的值替换变量?
- 您将如何解析该公式?
谢谢!!
最佳答案
是的,你可以做到这一点。这属于“将 NSPredicate
用于不适合的事情”的类别,但效果很好。
您需要将变量替换为以 $
开头的单个单词,因为 NSPredicate
就是这样表示变量的:
NSPredicate *p = [NSPredicate predicateWithFormat:@"foo = $bar"];
不管怎样,你想这么做,那就太好了。 NSRegularExpression
是一个很好的方法。
一旦你这样做了,你就会得到这样的东西:
@"$profitability2011 = $profit2011 / $revenue2011"
然后您可以通过+predicateWithFormat:
弹出它。您将返回一个 NSComparisonPredicate
。 -leftExpression
的类型为 NSVariableExpressionType
,并且 -rightExpression
的类型将为 NSFunctionExpressionType
。
这就是事情开始变得棘手的地方。如果你是 -evaluteWithObject:substitutionVariables:
,您只需返回 YES
或 NO
值,因为 predicate is simply a statement that evaluates to true or false 。我还没有探索如何只评估一侧(在本例中为 -rightExpression
),但有可能 -[NSExpression expressionValueWithObject:context:]
可能对你有帮助。我不知道,因为我不确定“上下文”参数的用途。它看起来不像是一个替换字典,但我可能是错的。
所以,如果这不起作用(我不知道它是否会起作用),你可以使用我的解析器:DDMathParser 。它有一个解析器,类似于 NSPredicate 的解析器,但专门针对解析和评估数学表达式进行了调整。在你的情况下,你会这样做:
#import "DDMathParser.h"
NSString *s = @"$profit2011 / $revenue2011";
NSDictionary *values = ...; // the values of the variables
NSNumber *profitability = [s numberByEvaluatingStringWithSubstitutions:values];
DDMathParser
的文档 is quite extensive ,而且它可以做很多事情。
编辑动态变量分辨率
我刚刚推送了一项更改,允许 DDMathParser 动态解析函数。理解函数与变量的不同非常重要。函数被求值,而变量被简单地替换。但是,此更改仅对函数进行动态解析,而不是对变量进行动态解析。没关系,因为 DDMathParser 有一个叫做 argumentless functions 的巧妙东西。 .
无参数函数是指后面不跟左括号的函数名称。为了方便起见,它已为您插入。这意味着 @"pi"
被正确解析为 @"pi()"
(因为 π 的常量是作为函数实现的)。
根据您的情况,您可以这样做:
无需重新调整字符串来创建变量,只需使用术语名称即可:
@"profit_2011 / revenue_2011";
这将被解析,就像您输入了:
@"divide(profit_2011(), revenue_2011())"
您可以使用函数解析器设置您的 DDMathEvaluator
对象。 DDMathParser
存储库中有两个示例:
- This example展示如何使用解析器函数在替换字典中查找“缺失”函数(这最像您想要的)
- This example向您展示如何解释任何缺失的函数,就像它的计算结果为 42 一样。
一旦实现了解析器函数,您就可以不必将所有变量打包到字典中。
关于objective-c - 使用 NSPredicate 解析带变量的公式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9400886/