0

I have a string with multiple digits and operators

@"5+4-9/10".

How to get the result from it?

I want to use it within the calculator i am using. I will have to display the result dynamically when a digit or operator is pressed.

I used arity jar file in android. But i am not able to achieve something like that in iPhone.

DMK
  • 2,448
  • 1
  • 24
  • 35
Chandra Sekhar
  • 177
  • 1
  • 11

3 Answers3

9

What about this -

NSString *formula = @"1+5*6";
NSExpression *exp = [NSExpression expressionWithFormat:formula];
NSNumber *resultForCustomFormula = [exp expressionValueWithObject:nil context:nil];
NSLog(@"%f", [resultForCustomFormula floatValue]);

EDIT : Now I thought about your requirement and made a method using NSScanner You will not believe I didn't use NSScanner before Mr. Borrrden suggested me to use it and I found it awesome. See below method -

-(NSMutableString *)formatString:(NSString *)formula
{
    // Let's check if there any wrong (.) value exm: 1/.2 or .7+3 
    // 1/0.2 and 0.7+3 are okay but above are incorrect so first fix them

    NSString *str = formula;
    NSInteger c = 0;
    for(int i=0; i<[str length]; i++)
    {

        if([[NSString stringWithFormat:@"%c",[str characterAtIndex:i]] isEqualToString:@"+"] ||
           [[NSString stringWithFormat:@"%c",[str characterAtIndex:i]] isEqualToString:@"-"] ||
           [[NSString stringWithFormat:@"%c",[str characterAtIndex:i]] isEqualToString:@"/"] ||
           [[NSString stringWithFormat:@"%c",[str characterAtIndex:i]] isEqualToString:@"*"])
        {
            if([str length] > i+1)
            {
                if([[NSString stringWithFormat:@"%c",[str characterAtIndex:i+1]] isEqualToString:@"."])
                {
                    formula = [formula stringByReplacingCharactersInRange:NSMakeRange(i+1+c, 1) withString:@"0."];
                    c++;
                }
            }
        }
    }

    // Now we will convert all numbers in float

    NSString *aString;
    float aFloat;
    NSMutableString *formattedString = [[NSMutableString alloc]init];

    NSScanner *theScanner = [NSScanner scannerWithString:formula];
    while ([theScanner isAtEnd] == NO) 
    {

        if([theScanner scanFloat:&aFloat])
        {
            [formattedString appendString:[NSString stringWithFormat:@"%f",aFloat]];
        }

        if([theScanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:&aString])
        {
            [formattedString appendString:aString];
        }
    }
    return formattedString;
}

This will convert (2.222/.4)+9999-7+0.7*.13 in to (2.222000/0.400000)+9999.000000-7.000000+0.700000*0.130000.
Just call this method before using NSExpression.

NSString *formula = @"(2.222/.4)+9999-7+0.7*.13";
NSString *formattedString = [self formatString:formula];
NSExpression *exp = [NSExpression expressionWithFormat:formattedString];
NSNumber *resultForCustomFormula = [exp expressionValueWithObject:nil context:nil];
NSLog(@"Result = %f", [resultForCustomFormula floatValue]);

//OutPut: Result = 9997.646484

Note: I'm not saying that it will work in all formula strings. May be it will not work in some case. But it will work in general equations.

Community
  • 1
  • 1
TheTiger
  • 13,264
  • 3
  • 57
  • 82
  • i am getting the floor value.i tried 7/4 and its returning 1.0000 – Chandra Sekhar Jan 04 '13 at 11:19
  • Yeah because 7 and 4 are integers so surely you will get 1.0000 try it with floats like 7.0/4.0 then see :) – TheTiger Jan 04 '13 at 11:26
  • Is there method to validate expression because i want to show the result dynamically – Chandra Sekhar Jan 08 '13 at 10:25
  • What do you mean by validate Expression ? can you give any example what you actually want ? – TheTiger Jan 08 '13 at 10:37
  • i am typing the expression in the textfield and displaying the result in a label. i want to show show the result spontaneously . i will keep typing 2*4+3-44 something and i want to get the answer dynamically everytime i press the digit. – Chandra Sekhar Jan 08 '13 at 10:44
  • The code u gave me works great but i need to press the equal button to get the answer.which i want to avoid – Chandra Sekhar Jan 08 '13 at 10:45
  • Then no need to validate expression Just call above method every time when you press the digit ... but on pressing digit calculating the result is not good what if user want to press second digit ? Would be better if you calculate the equation after `operator`pressed or on `equal` button click ... On `equal` button click what is your issue ? – TheTiger Jan 08 '13 at 10:48
  • ya it has to work if the user presses second didgit also 2*2 the label should show 4 and and if one more 2 is pressed it will be 2*22 and it should show 44.Its a requirement asked by my TL. – Chandra Sekhar Jan 08 '13 at 11:09
  • 1
    So dear its not about expression validation you will have to do it your self its all about logics :) – TheTiger Jan 08 '13 at 11:26
  • Please write some words about down vote. I can correct my mistake. – TheTiger Jun 27 '13 at 17:37
  • 2
    The problem with this approach is that you are trying to parse a string the same way another parser (`NSExpression`) does. Parsing is hard and the attempt to imitate another parser usually fails, at least for many input cases). One example: @"1/.2". Even if you fix this case I'm sure there are others. So the problem is the general approach you chose. That's why I downvoted. – Nikolai Ruhe Jun 27 '13 at 17:42
  • @NikolaiRuhe - Okay!! So you mean it can not be done ?? Well I would try it. Thanks for telling me the mistake. You are good tester :) – TheTiger Jun 27 '13 at 17:46
  • 1
    The main problem is left untouched (or even worsened). You added code to fix one special case where your code failed. I still can see many other cases that don't work. Yet, the reason why I consider this a bad solution is, as I described, the general approach of trying to imitate a non-trivial parser. – Nikolai Ruhe Jun 28 '13 at 08:49
  • @NikolaiRuhe - So what is the best solution ? – TheTiger Jun 28 '13 at 08:55
  • And answer is still deserves down vote ??? I agree it will not work in all case but it is better than others. – TheTiger Jun 28 '13 at 09:09
  • 2
    @TheTiger I disagree that it's better than others. This kind of code that holds uncounted hidden bugs is what makes projects fail in the long term. I've seen projects go down just because debugging costs exploded. The root of the problems were programmers that, on the surface, were fast with implementing features but never took the time to understand what the implications of their code were. – Nikolai Ruhe Jun 28 '13 at 09:18
  • @NikolaiRuhe - I didn't mean its better than all I mean was others who answered here on this page. Can you tell what approach will work here ? I would like to know. – TheTiger Jun 28 '13 at 09:25
3

Note that : You have to pass at least one float value.

I know that this is not the Best way , But Something like this can work for you.

NSString *formula = @"5+4-9/10";
NSString *str = [formula lastPathComponent];
formula = [formula stringByReplacingOccurrencesOfString:str withString:[NSString stringWithFormat:@"%@.0",str]];
NSString *strCal=[NSString stringWithString:formula];
NSExpression *exp=[NSExpression expressionWithFormat:strCal];
float result=[[exp expressionValueWithObject:nil context:nil] floatValue];
NSLog(@"result:%f",result);

You can use GCMathParser or DDMathParser.

Don't know if this is the most efficient method or not but Wrote to help you anyway...!!!

Bhavin
  • 27,155
  • 11
  • 55
  • 94
0

You could parse "all" numbers to float:

NSMutableString *numericExpression = [NSMutableString stringWithString:@"4+3/2-7/4"];

NSMutableString *nExp=[NSMutableString stringWithString:@""];
BOOL innum=false;
BOOL dotfound=false;

for (NSInteger charIdx=0; charIdx<numericExpression.length; charIdx++){
        NSString *substr=[NSString stringWithFormat:@"%C",[numericExpression characterAtIndex:charIdx]];
        if (isdigit([numericExpression characterAtIndex:charIdx])) {
            // in number
            innum=true;
        }else if ([substr isEqualToString:@"."]){
            // dot found ...
            innum=true;
            dotfound=true;
        }else{
            // not in number
            if (innum && dotfound) {
                NSLog(@"all good (*).*");
            }else if(innum && !dotfound){
                NSLog(@"adding .0");
                [nExp appendString:@".0"];
            }
            innum=false;
            dotfound=false;
        }
    [nExp appendString:substr];
    NSLog(@"%@",nExp);
}

NSExpression *expression = [NSExpression expressionWithFormat:nExp];
NSNumber *result = [expression expressionValueWithObject:nil context:nil];
 NSLog(@"calc %@ = %@",nExp,result);
JCPU
  • 1