Objective c 如何将NSString方程解析为树?目标-C

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

我正在尝试解析一个布尔方程,它当前的形式是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*数据


感谢要将字符串解析为树(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
    节点的子表达式
  • 由于DDMathParser解析字符串的方式决定,
    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
    节点的子表达式
  • 由于DDMathParser解析字符串的方式决定,
    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,但它看起来非常复杂,我更容易编写自己的解析器,先用或然后用括号拆分方程,然后递归处理括号。