Objective c 如何将NSString方程解析为树?目标-C
我正在尝试解析一个布尔方程,它当前的形式是NSString 我想把它解析成一棵树,这样我就可以操纵这个表达式并将其简化为最简单的形式 就像Wolfram Alpha能够做到的那样 简化输入:Objective c 如何将NSString方程解析为树?目标-C,objective-c,ios,parsing,boolean,algebra,Objective C,Ios,Parsing,Boolean,Algebra,我正在尝试解析一个布尔方程,它当前的形式是NSString 我想把它解析成一棵树,这样我就可以操纵这个表达式并将其简化为最简单的形式 就像Wolfram Alpha能够做到的那样 简化输入: (A and (A or B) or (B and A) or not(A)) and (B or not (A)) 到 我的问题是将等式解析为树对象,其中每个树节点都有3个属性: 1.TreeNode*父级 2.NSMutableArray*子级 3.NSString*数据 感谢要将字符串解析为树(A
(A and (A or B) or (B and A) or not(A)) and (B or not (A))
到
我的问题是将等式解析为树对象,其中每个树节点都有3个属性:
1.TreeNode*父级
2.NSMutableArray*子级
3.NSString*数据
感谢要将字符串解析为树(AST),您需要两个组件:一个lexer,它将字符串拆分为单独的“标记”-括号、运算符、标识符,以及一个解析器,它从lexer中逐个使用标记并构建树。对于可能要使用NSScanner的lexer,语法分析器很容易手工编写(例如,请参阅),或者您可以使用yacc或Lemon之类的工具。要将字符串解析为树(AST),您需要两个组件:lexer,它将字符串拆分为单独的“标记”-括号、运算符、标识符,还有一个解析器,它逐个使用lexer中的令牌并构建树。对于可能要使用NSScanner的lexer,语法分析器很容易手工编写(例如,请参阅),或者您可以使用yacc或Lemon之类的工具。只需稍加修改即可处理此问题:
#import "DDMathParser.h"
NSString *source = @"(A and (A or B) or (B and A) or not(A)) and (B or not (A))";
source = [source stringByReplacingOccurrencesOfString:@" and " withString:@" && "];
source = [source stringByReplacingOccurrencesOfString:@" or " withString:@" || "];
NSError *error = nil;
DDExpression *e = [DDExpression expressionFromString:source error:&error];
if (e) {
// it successfully parsed
}
至于简化表达式,这在本文中有充分的解释。我不确定是否有任何逻辑表达式的重写规则(应用DeMorgan定律等),但这些规则并不难添加
关于您的要求:
dExpression
节点都有一个parentExpression
只读属性参数
属性访问dExpression
节点的子表达式a
和B
实际上将被解析为a()
和B()
(即不带参数的函数)。如果您希望将它们解析为“变量”表达式,则它们前面需要一个$
:$a
,等等。这意味着您可以使用函数
属性来访问对象的名称,而不是变量
属性#import "DDMathParser.h"
NSString *source = @"(A and (A or B) or (B and A) or not(A)) and (B or not (A))";
source = [source stringByReplacingOccurrencesOfString:@" and " withString:@" && "];
source = [source stringByReplacingOccurrencesOfString:@" or " withString:@" || "];
NSError *error = nil;
DDExpression *e = [DDExpression expressionFromString:source error:&error];
if (e) {
// it successfully parsed
}
至于简化表达式,这在本文中有充分的解释。我不确定是否有任何逻辑表达式的重写规则(应用DeMorgan定律等),但这些规则并不难添加
关于您的要求:
dExpression
节点都有一个parentExpression
只读属性参数
属性访问dExpression
节点的子表达式a
和B
实际上将被解析为a()
和B()
(即不带参数的函数)。如果您希望将它们解析为“变量”表达式,则它们前面需要一个$
:$a
,等等。这意味着您可以使用函数
属性来访问对象的名称,而不是变量
属性好的,谢谢你的帮助,这是我编写的最后一个Objective-C代码,用于将布尔表达式解析为树: 它采用如下表达式:
A AND B OR C AND NOT(B)
形式如下:
A.B + C./b
它适用于具有优先权的括号解析:
-(TreeNode *)ParseStringIntoTree:(NSString *)InputString{ //input string to parse
//returns root-node of tree
TreeNode *first=[[TreeNode alloc] init];
TreeNode *current=first;
NSString *workingString = [NSString stringWithString:InputString];
if (([workingString characterAtIndex:0]=='(') && ([workingString characterAtIndex:workingString.length-1]==')')) {
NSRange boop={1,workingString.length-2};
workingString=[workingString substringWithRange:boop];
}
int brackCount=0;
bool plussesLeft=FALSE;
for (int pos=0; pos<workingString.length; pos++) {
char currentC=[workingString characterAtIndex:pos];
//1
if (currentC=='(') {
brackCount++;
}
//2
if (currentC==')') {
brackCount--;
}
if (currentC=='+' && brackCount==0){
plussesLeft=TRUE;
}
}
//############ PARSE plus signs with BRACKETS
brackCount=0;
int prevPlusPos=-1;
if (plussesLeft) {
for (int pos=0; pos<workingString.length; pos++) {
char currentC=[workingString characterAtIndex:pos];
//1
if (currentC=='(') {
brackCount++;
}
//2
if (currentC==')') {
brackCount--;
}
//3
if (currentC=='+'&&brackCount==0) {
NSRange boop={prevPlusPos+1, pos-prevPlusPos-1};
NSString *toParse=[workingString substringWithRange:boop];
TreeNode *child;
if(toParse.length>1){child=[self ParseStringIntoTree:toParse];}
else{child=[TreeNode newTreeNodeWithValue:toParse];}
[current addChild:child];
[current setValue:@"+"];
prevPlusPos=pos;
}
//4
if (pos==workingString.length-1 &&brackCount==0 && prevPlusPos!=-1) {
NSRange boop={prevPlusPos+1, pos-prevPlusPos};
NSString *toParse=[workingString substringWithRange:boop];
TreeNode *child;
if(toParse.length>1){child=[self ParseStringIntoTree:toParse];}
else{child=[TreeNode newTreeNodeWithValue:toParse];};
[current addChild:child];
[current setValue:@"+"];
}
}
}
//############ finish PARSE plus signs with BRACKETS
BOOL dotsLeft=FALSE;
for (int pos=0; pos<workingString.length; pos++) {
char currentC=[workingString characterAtIndex:pos];
//1
if (currentC=='(') {
brackCount++;
}
//2
if (currentC==')') {
brackCount--;
}
if (currentC=='.' && brackCount==0){
dotsLeft=TRUE;
}
}
int prevDotPos=-1;
if (!plussesLeft && dotsLeft) {
for (int pos=0; pos<workingString.length; pos++) {
char currentC=[workingString characterAtIndex:pos];
//1
if (currentC=='(') {
brackCount++;
}
//2
if (currentC==')') {
brackCount--;
}
//3
if (currentC=='.' && brackCount==0 && prevPlusPos==-1) {
NSRange boop={prevDotPos+1, pos-prevDotPos-1};
NSString *toParse=[workingString substringWithRange:boop];
TreeNode *child;
if(toParse.length>1){child=[self ParseStringIntoTree:toParse];}
else{child=[TreeNode newTreeNodeWithValue:toParse];}
[current addChild:child];
[current setValue:@"."];
prevDotPos=pos;
}
//4
if (pos==workingString.length-1 &&brackCount==0 && prevDotPos!=-1) {
NSRange boop={prevDotPos+1, pos-prevDotPos};
NSString *toParse=[workingString substringWithRange:boop];
TreeNode *child;
if(toParse.length>1){child=[self ParseStringIntoTree:toParse];}
else{child=[TreeNode newTreeNodeWithValue:toParse];};
[current addChild:child];
[current setValue:@"."];
}
}
//left with current being the
}
if (!plussesLeft && !dotsLeft) {
if ([workingString characterAtIndex:0]=='/') {
TreeNode *child=[self ParseStringIntoTree:[workingString substringFromIndex:1]];
[current addChild:child];
[current setValue:@"/"];
}
if (workingString.length==1) {
[current setValue:workingString];
}
}
return first;
}
这些方法按照这些名称所暗示的方式执行。
希望这能帮助将来寻找解析器的任何人,无论是专门针对布尔代数还是作为其他解析器的基础 好的,谢谢你的帮助,这是我为将布尔表达式解析为树而编写的最终目标C代码: 它采用如下表达式:
A AND B OR C AND NOT(B)
形式如下:
A.B + C./b
它适用于具有优先权的括号解析:
-(TreeNode *)ParseStringIntoTree:(NSString *)InputString{ //input string to parse
//returns root-node of tree
TreeNode *first=[[TreeNode alloc] init];
TreeNode *current=first;
NSString *workingString = [NSString stringWithString:InputString];
if (([workingString characterAtIndex:0]=='(') && ([workingString characterAtIndex:workingString.length-1]==')')) {
NSRange boop={1,workingString.length-2};
workingString=[workingString substringWithRange:boop];
}
int brackCount=0;
bool plussesLeft=FALSE;
for (int pos=0; pos<workingString.length; pos++) {
char currentC=[workingString characterAtIndex:pos];
//1
if (currentC=='(') {
brackCount++;
}
//2
if (currentC==')') {
brackCount--;
}
if (currentC=='+' && brackCount==0){
plussesLeft=TRUE;
}
}
//############ PARSE plus signs with BRACKETS
brackCount=0;
int prevPlusPos=-1;
if (plussesLeft) {
for (int pos=0; pos<workingString.length; pos++) {
char currentC=[workingString characterAtIndex:pos];
//1
if (currentC=='(') {
brackCount++;
}
//2
if (currentC==')') {
brackCount--;
}
//3
if (currentC=='+'&&brackCount==0) {
NSRange boop={prevPlusPos+1, pos-prevPlusPos-1};
NSString *toParse=[workingString substringWithRange:boop];
TreeNode *child;
if(toParse.length>1){child=[self ParseStringIntoTree:toParse];}
else{child=[TreeNode newTreeNodeWithValue:toParse];}
[current addChild:child];
[current setValue:@"+"];
prevPlusPos=pos;
}
//4
if (pos==workingString.length-1 &&brackCount==0 && prevPlusPos!=-1) {
NSRange boop={prevPlusPos+1, pos-prevPlusPos};
NSString *toParse=[workingString substringWithRange:boop];
TreeNode *child;
if(toParse.length>1){child=[self ParseStringIntoTree:toParse];}
else{child=[TreeNode newTreeNodeWithValue:toParse];};
[current addChild:child];
[current setValue:@"+"];
}
}
}
//############ finish PARSE plus signs with BRACKETS
BOOL dotsLeft=FALSE;
for (int pos=0; pos<workingString.length; pos++) {
char currentC=[workingString characterAtIndex:pos];
//1
if (currentC=='(') {
brackCount++;
}
//2
if (currentC==')') {
brackCount--;
}
if (currentC=='.' && brackCount==0){
dotsLeft=TRUE;
}
}
int prevDotPos=-1;
if (!plussesLeft && dotsLeft) {
for (int pos=0; pos<workingString.length; pos++) {
char currentC=[workingString characterAtIndex:pos];
//1
if (currentC=='(') {
brackCount++;
}
//2
if (currentC==')') {
brackCount--;
}
//3
if (currentC=='.' && brackCount==0 && prevPlusPos==-1) {
NSRange boop={prevDotPos+1, pos-prevDotPos-1};
NSString *toParse=[workingString substringWithRange:boop];
TreeNode *child;
if(toParse.length>1){child=[self ParseStringIntoTree:toParse];}
else{child=[TreeNode newTreeNodeWithValue:toParse];}
[current addChild:child];
[current setValue:@"."];
prevDotPos=pos;
}
//4
if (pos==workingString.length-1 &&brackCount==0 && prevDotPos!=-1) {
NSRange boop={prevDotPos+1, pos-prevDotPos};
NSString *toParse=[workingString substringWithRange:boop];
TreeNode *child;
if(toParse.length>1){child=[self ParseStringIntoTree:toParse];}
else{child=[TreeNode newTreeNodeWithValue:toParse];};
[current addChild:child];
[current setValue:@"."];
}
}
//left with current being the
}
if (!plussesLeft && !dotsLeft) {
if ([workingString characterAtIndex:0]=='/') {
TreeNode *child=[self ParseStringIntoTree:[workingString substringFromIndex:1]];
[current addChild:child];
[current setValue:@"/"];
}
if (workingString.length==1) {
[current setValue:workingString];
}
}
return first;
}
这些方法按照这些名称所暗示的方式执行。
希望这能帮助将来寻找解析器的任何人,无论是专门针对布尔代数还是作为其他解析器的基础 +1如果您能保证字符串格式正确,那么编写RD解析器可能非常简单。为此,我查看了wikipedia条目,但仍然不清楚如何准确编写解析器,还有其他提示吗?@Tawfikh:使用解析器生成器为您创建解析器。我建议是因为它的简单性。我看了Lemon,但它看起来非常复杂,我更容易编写自己的解析器,先按或然后按拆分方程,然后递归处理括号。+1如果你能保证字符串格式正确,编写RD解析器可能非常简单。谢谢你,我已经看过维基百科的条目,但是对于如何准确地编写解析器,还有什么提示吗?@tawfikh:使用解析器生成器为您创建解析器。我建议是因为它的简单性。我看了Lemon,但它看起来非常复杂,我更容易编写自己的解析器,先用或然后用括号拆分方程,然后递归处理括号。