objective-c - 使用 NSPredicate 解析带变量的公式

标签 objective-c ios regex nsstring nspredicate

任务:

我计划解析 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: ,您只需返回 YESNO 值,因为 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 存储库中有两个示例:

  1. This example展示如何使用解析器函数在替换字典中查找“缺失”函数(这最像您想要的)
  2. This example向您展示如何解释任何缺失的函数,就像它的计算结果为 42 一样。

一旦实现了解析器函数,您就可以不必将所有变量打包到字典中。

关于objective-c - 使用 NSPredicate 解析带变量的公式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9400886/

相关文章:

ios - Today Extension 在 iOS 8.1.2 上启动前崩溃

ios - iOS 上的 sqlite3 中的 "No such function: REGEXP"

ios - 快速搜索栏 Controller

javascript - 末尾数字和空格的正则表达式

c# - 您如何使用正则表达式来替换特定的匹配项(例如 "last"或 "second to last")?

iPhone Core Data 获取日期操作

ios - 显示 ABPersonViewController 的这段代码有什么问题?

objective-c - iOS 是否有任何支持格式化数字的库,例如 Mac OSX 的 NSNumberFormatter?

ios - WebView 内容未正确缩放

regex - 如何使用 Regexp 包 ReplaceAll 函数替换 Go 中的字符?