diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj index f1458ea..dcd0f2c 100644 --- a/Demo/Demo.xcodeproj/project.pbxproj +++ b/Demo/Demo.xcodeproj/project.pbxproj @@ -18,7 +18,9 @@ BE25BBBA16C869840087A092 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BE25BBB916C869840087A092 /* Default-568h@2x.png */; }; BE25BBBD16C869840087A092 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BE25BBBC16C869840087A092 /* ViewController.m */; }; BE25BBC016C869840087A092 /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = BE25BBBE16C869840087A092 /* ViewController.xib */; }; + BE2EF96517F31CAF008FDF8C /* GIDACalculateTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2EF96417F31CAF008FDF8C /* GIDACalculateTextField.m */; }; BE98117816C86A9A0034F489 /* GIDACalculateString.m in Sources */ = {isa = PBXBuildFile; fileRef = BE98117716C86A9A0034F489 /* GIDACalculateString.m */; }; + BEA256B417F47ABD008AB340 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEA256B217F47A78008AB340 /* Accelerate.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -38,8 +40,11 @@ BE25BBBB16C869840087A092 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; BE25BBBC16C869840087A092 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; BE25BBBF16C869840087A092 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController.xib; sourceTree = ""; }; + BE2EF96317F31CAF008FDF8C /* GIDACalculateTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GIDACalculateTextField.h; sourceTree = ""; }; + BE2EF96417F31CAF008FDF8C /* GIDACalculateTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GIDACalculateTextField.m; sourceTree = ""; }; BE98117616C86A9A0034F489 /* GIDACalculateString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GIDACalculateString.h; sourceTree = ""; }; BE98117716C86A9A0034F489 /* GIDACalculateString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GIDACalculateString.m; sourceTree = ""; }; + BEA256B217F47A78008AB340 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -47,6 +52,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + BEA256B417F47ABD008AB340 /* Accelerate.framework in Frameworks */, BE25BBA416C869840087A092 /* UIKit.framework in Frameworks */, BE25BBA616C869840087A092 /* Foundation.framework in Frameworks */, BE25BBA816C869840087A092 /* CoreGraphics.framework in Frameworks */, @@ -76,6 +82,7 @@ BE25BBA216C869840087A092 /* Frameworks */ = { isa = PBXGroup; children = ( + BEA256B217F47A78008AB340 /* Accelerate.framework */, BE25BBA316C869840087A092 /* UIKit.framework */, BE25BBA516C869840087A092 /* Foundation.framework */, BE25BBA716C869840087A092 /* CoreGraphics.framework */, @@ -92,6 +99,8 @@ BE25BBB316C869840087A092 /* AppDelegate.m */, BE25BBBB16C869840087A092 /* ViewController.h */, BE25BBBC16C869840087A092 /* ViewController.m */, + BE2EF96317F31CAF008FDF8C /* GIDACalculateTextField.h */, + BE2EF96417F31CAF008FDF8C /* GIDACalculateTextField.m */, BE25BBBE16C869840087A092 /* ViewController.xib */, BE25BBAA16C869840087A092 /* Supporting Files */, ); @@ -178,6 +187,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + BE2EF96517F31CAF008FDF8C /* GIDACalculateTextField.m in Sources */, BE25BBB016C869840087A092 /* main.m in Sources */, BE25BBB416C869840087A092 /* AppDelegate.m in Sources */, BE25BBBD16C869840087A092 /* ViewController.m in Sources */, @@ -264,6 +274,7 @@ BE25BBC416C869840087A092 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Demo/Demo-Prefix.pch"; INFOPLIST_FILE = "Demo/Demo-Info.plist"; @@ -275,6 +286,7 @@ BE25BBC516C869840087A092 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Demo/Demo-Prefix.pch"; INFOPLIST_FILE = "Demo/Demo-Info.plist"; diff --git a/Demo/Demo/AppDelegate.m b/Demo/Demo/AppDelegate.m index dec6eb4..5afbd67 100644 --- a/Demo/Demo/AppDelegate.m +++ b/Demo/Demo/AppDelegate.m @@ -12,18 +12,11 @@ @implementation AppDelegate -- (void)dealloc -{ - [_window release]; - [_viewController release]; - [super dealloc]; -} - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. - self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease]; + self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; diff --git a/Demo/Demo/GIDACalculateString.h b/Demo/Demo/GIDACalculateString.h index d98916c..88b6580 100644 --- a/Demo/Demo/GIDACalculateString.h +++ b/Demo/Demo/GIDACalculateString.h @@ -19,3 +19,9 @@ +(NSNumber *)solveString:(NSString *)string; @end + +@interface ComplexObject : NSObject +@property (nonatomic) double real; +@property (nonatomic) double imaginary; +-(NSString *)stringValue; +@end \ No newline at end of file diff --git a/Demo/Demo/GIDACalculateString.m b/Demo/Demo/GIDACalculateString.m index 74f7d8f..5b799bb 100644 --- a/Demo/Demo/GIDACalculateString.m +++ b/Demo/Demo/GIDACalculateString.m @@ -7,33 +7,129 @@ // #import "GIDACalculateString.h" +#import enum { - GIDAOperatorNone = 0, - GIDAOperatorOpenParentheses = 1, - GIDAOperatorCloseParentheses = 2, - GIDAOperatorFraction = 3, - GIDAOperatorTimes = 4, - GIDAOperatorPlus = 5, - GIDAOperatorMinus = 6 + GIDAOperatorNone, + GIDAOperatorOpenParentheses, + GIDAOperatorCloseParentheses, + GIDAOperatorFraction, + GIDAOperatorTimes, + GIDAOperatorPlus, + GIDAOperatorMinus, + GIDAOperatorRoot }; typedef NSUInteger GIDAOperator; -@interface GIDACalculateString () +@interface ComplexObject () +@property (nonatomic) double radius; +@property (nonatomic) double angle; +@end + +@implementation ComplexObject +-(id)initWithReal:(double)r andImaginary:(double)i { + self = [super init]; + if (self) { + _real = r; + _imaginary = i; + _radius = sqrt(pow(r,2)+pow(i,2)); + if (_real != 0) { + if (_imaginary == 0) { + _angle = 0; + } else { + _angle = asin(i/_radius); + } + } else { + if (_imaginary != 0) { + _angle = 90.0; + } else { + _angle = 0.0; + } + } + + } + return self; +} +-(void)setReal:(double)real { + _real = real; + _radius = sqrt(pow(_real,2)+pow(_imaginary,2)); + if (_real != 0) { + if (_imaginary == 0) { + _angle = 0; + } else { + _angle = asin(_imaginary/_radius); + } + } else { + if (_imaginary != 0) { + _angle = 90.0; + } else { + _angle = 0.0; + } + } +} +-(void)setImaginary:(double)imaginary { + _imaginary = imaginary; + _radius = sqrt(pow(_real,2)+pow(_imaginary,2)); + if (_real != 0) { + if (_imaginary == 0) { + _angle = 0; + } else { + _angle = asin(_imaginary/_radius); + } + } else { + if (_imaginary != 0) { + _angle = 90.0; + } else { + _angle = 0.0; + } + } +} +-(void)squareRoot { + if (_real < 0) { + _angle = 90.0; + } else { + _angle = _angle / 2.0; + } + + _radius = sqrt(_radius); + double rad = _angle * M_PI / 180.0; + _real = _radius * cos(rad); + if (_angle == 90.0) { + _real = 0; + } + + _imaginary = _radius * sin(rad); + if (_imaginary == 0 || _imaginary == -0) { + _imaginary = 0; + } + NSLog(@"%f",_angle); +} +-(NSString *)stringValue{ + if ((_real > 0 || _real < -0) && _imaginary != 0 ) { + return [NSString stringWithFormat:@"%f+%fi",self.real, self.imaginary]; + } + if (_real == 0 && _imaginary != 0) { + return [NSString stringWithFormat:@"%fi", self.imaginary]; + } + if (_real != 0 && _imaginary == 0) { + return [NSString stringWithFormat:@"%f", self.real]; + } + return @"0"; +} + +@end + +@interface GIDACalculateString () +(BOOL)checkFor:(char)character inThis:(NSString *)string fromThis:(int)position whereThisAre:(NSCharacterSet *)notAllowed andThisHelps:(NSCharacterSet *)toStop; +(BOOL)checkThis:(NSString *)string atThis:(int)position ifLeftDoesNotHave:(NSCharacterSet *)leftCheck norRightHas:(NSCharacterSet *)rightCheck allowFirst:(BOOL)first; +(int)openParenthesesFor:(NSString *)string toLocation:(int)position; +(NSString *)fixString:(NSString *)string; -+(NSNumber *)solveString:(NSString *)string andOperator:(GIDAOperator)operator; -+(NSArray *)splitString:(NSString *)string byOperator:(GIDAOperator)operator; -+(NSArray *)splitFirstParentheses:(NSString *)string; @end @implementation GIDACalculateString - //String appending newString to String. +(NSString *)stringFrom:(NSString *)string withThis:(NSString *)newString { return [string stringByAppendingString:newString]; @@ -181,7 +277,7 @@ +(BOOL)usingThis:(NSString *)string addThis:(NSString *)newString here:(NSRange) //If its the first character to input, check if it is an allowed character. //Allowed characters as first character of input are '.', '-', '(' and numbers from 0 to 9. if ([string length] == 0 || range.location == 0) { - if ([newString characterAtIndex:0] == '.' || [newString characterAtIndex:0] == '-' || [newString characterAtIndex:0] == '(' || ([newString characterAtIndex:0] >= '0' && [newString characterAtIndex:0] <= '9')) { + if ([newString characterAtIndex:0] == '.' || [newString characterAtIndex:0] == '-' || [newString characterAtIndex:0] == '(' || ([newString characterAtIndex:0] >= '0' && [newString characterAtIndex:0] <= '9')) { success = YES; } else { success = NO; @@ -208,7 +304,7 @@ +(BOOL)usingThis:(NSString *)string addThis:(NSString *)newString here:(NSRange) success = [self checkThis:string atThis:range.location ifLeftDoesNotHave:left norRightHas:right allowFirst:NO]; break; case '-': - //The user is not allowed to put a '+' sign when on the left there is a '-'. + //The user is not allowed to put a '-' sign when on the left there is a '-'. //To the right of a '-' sign there can not be a ')', '+', '-', '*', or '/'. left = [NSCharacterSet characterSetWithCharactersInString:@"-"]; right = [NSCharacterSet characterSetWithCharactersInString:@"+-*/)"]; @@ -272,8 +368,12 @@ +(NSString *)fixString:(NSString *)string { [mutable replaceOccurrencesOfString:@"(-" withString:@"OM" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"*-" withString:@"TM" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"/-" withString:@"FM" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + [mutable replaceOccurrencesOfString:@"√-" withString:@"NR" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"+-" withString:@"PM" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + [mutable replaceOccurrencesOfString:@"-" withString:@"+-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + + [mutable replaceOccurrencesOfString:@"NR" withString:@"√-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"MM" withString:@"+" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"PM" withString:@"+-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"FM" withString:@"/-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; @@ -281,235 +381,409 @@ +(NSString *)fixString:(NSString *)string { [mutable replaceOccurrencesOfString:@"OM" withString:@"(-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"CM" withString:@")+-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"BM" withString:@"-1*(" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; - [mutable replaceOccurrencesOfString:@"CO" withString:@")*(" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + [mutable replaceOccurrencesOfString:@"CO" withString:@")*(" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; return mutable; } -//Split in string in 3 parts. -//Before the first parentheses -//The parentheses, between open and close. -//After the parentheses. -//If all string is the parentheses then it is put in the middle and empty trings on the sides. -+(NSArray *)splitFirstParentheses:(NSString *)string { - int i = 0; - NSArray *parentheses = nil; - - //Look for the first '(' - for (i = 0; i < [string length]; i++) { - if ([string characterAtIndex:i] == '(') { - break; - } - } - NSString *pre = [string substringToIndex:i]; ++(ComplexObject *)parenthesisAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; - //Did it find a '(' - if (i == [string length]) { - //Did not find a '(', put string in the middle. - parentheses = [NSArray arrayWithObjects:@"",pre, @"", nil]; - } else { - //Did find a '('. - //If the there is a number before '(', then append to pre a '*'. (As it is a simplification) - if (i != 0) { - if ([string characterAtIndex:i-1] >= '0' && [string characterAtIndex:i-1] <= '9') { - pre = [pre stringByAppendingString:@"*"]; + regex = [NSRegularExpression regularExpressionWithPattern:@"(√)(-*(\\d|[.i])+)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + string = [regex stringByReplacingMatchesInString:string + options:0 + range:NSMakeRange(0, [string length]) + withTemplate:@"√($2)"]; + + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d)(√)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + string = [regex stringByReplacingMatchesInString:string + options:0 + range:NSMakeRange(0, [string length]) + withTemplate:@"$1*$2"]; + + + + regex = [NSRegularExpression regularExpressionWithPattern:@"\\(((\\d|[+-/*√i.])*)\\)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + int position = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; } - } - //par is string where the parentheses is. (without the parentheses) - NSString *par = [string substringFromIndex:i+1]; - - //Look for the close parentheses. Use open in case there are subparentheses inside. - int open = 0; - for (i = 0; i < [par length]; i++) { - if ([par characterAtIndex:i] == '('){ - open ++; - } else { - - if ([par characterAtIndex:i] == ')') { - if (open == 0) { - break; - } else { - open --; - } - } + + range = result.range; + + [splitString addObject:[string substringWithRange:NSMakeRange(position, (range.location)-position)]]; + position = range.location + range.length; + range.length -= 2; + range.location += 1; + NSString *sub = [string substringWithRange:range]; + ComplexObject *numb = [self plusAndRegEx:sub]; + if (!numb) { + return nil; } + [splitString addObject:numb]; + i++; } - - NSString *post = @""; - //If the last character of par is ) then remove it and have post be "". - //If it is not. Cut the string and put the ending part in post. - if (i < [par length] - 1){ - post = [par substringFromIndex:i+1]; - if ([post characterAtIndex:0] >= '0' && [post characterAtIndex:0] <= '9') { - post = [@"*" stringByAppendingString:post]; + if (!i) { + return [self plusAndRegEx:string]; + } else { + position = range.location + range.length + 1; + [splitString addObject:[string substringWithRange:NSMakeRange(position, [string length]-position)]]; + for (int i = 0; i < [splitString count]; i++) { + if ([[splitString objectAtIndex:i] isKindOfClass:[ComplexObject class]]) { + + ComplexObject *complex = (ComplexObject *)[splitString objectAtIndex:i]; + NSString *complexString = [complex stringValue]; + + [splitString setObject:complexString atIndexedSubscript:i]; + } } + return [self parenthesisAndRegEx:[splitString componentsJoinedByString:@""]]; + } - par = [par substringToIndex:i]; - - parentheses = [NSArray arrayWithObjects:pre, par, post, nil]; + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; } - return parentheses; } -//Split a string based on its GIDAOperator. -//Only exception is parentheses and minus. -//Minus does not require spliting as it is considered a negative adition. -//For parentheses call splitFirstPArentheses. -+(NSArray *)splitString:(NSString *)string byOperator:(GIDAOperator)operator { - NSArray *split = nil; - switch (operator) { - case GIDAOperatorOpenParentheses: - split = [self splitFirstParentheses:string]; - break; - case GIDAOperatorPlus: - split = [string componentsSeparatedByString:@"+"]; - break; - case GIDAOperatorTimes: - split = [string componentsSeparatedByString:@"*"]; - break; - case GIDAOperatorFraction: - split = [string componentsSeparatedByString:@"/"]; - break; - default: - break; ++(ComplexObject *)plusAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d|[-i*√/.])*" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + int position = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + + ComplexObject *times = [self timesAndRegEx:sub]; + [splitString addObject:times]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:[string doubleValue] andImaginary:0]; + return complex; + } else { + position = range.location + range.length + 1; + if (position < [string length]) { + [splitString addObject:[string substringWithRange:NSMakeRange(position, [string length]-position)]]; + } + ComplexObject *total = [[ComplexObject alloc] initWithReal:0 andImaginary:0]; + for (ComplexObject *part in splitString) { + total.real += part.real; + total.imaginary += part.imaginary; + } + return total; + } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; } - return split; + } -//Solve string based on operator. -+(NSNumber *)solveString:(NSString *)string andOperator:(GIDAOperator)operator { - float total = 0; - NSNumber *number = nil; - NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - NSNumber *temp = nil; - - //Split the string based on the GIDAOperator. - NSArray *split = [self splitString:string byOperator:operator]; - - //Go through the split string. - for (int i = 0; i < [split count]; i++) { - switch (operator) { - case GIDAOperatorPlus: - //Plus operation. - if (i == 0 && [[split objectAtIndex:i] isEqualToString:@""]){ - } else { - //Try to format to a number. - temp = [formatter numberFromString:[split objectAtIndex:i]]; - if (temp) { - //If it was a number add it to the total, and update number. - total += [temp floatValue]; - number = [NSNumber numberWithFloat:total]; ++(ComplexObject *)timesAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d|[-/i.√])*" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + int position = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + ComplexObject *times = [self divisionAndRegEx:sub]; + [splitString addObject:times]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:[string doubleValue] andImaginary:0]; + return complex; + } else { + position = range.location + range.length + 1; + if (position < [string length]) { + [splitString addObject:[string substringWithRange:NSMakeRange(position, [string length]-position)]]; + } + int firstreal = 0; + int firstimag = 0; + ComplexObject *total = [[ComplexObject alloc] initWithReal:0 andImaginary:0]; + int imagetimes = 0; + + for (ComplexObject *part in splitString) { + if (part.imaginary != 0) { + if (!firstimag){ + firstimag++; + total = part; } else { - //If not a number maybe it has '*' or '/'. So try with '*' - number = [self solveString:[split objectAtIndex:i] andOperator:GIDAOperatorTimes]; - if (!number) { - //Not a number then abort - i = [split count]; + total.imaginary *= part.imaginary; + } + imagetimes++; + } else { + if (firstimag) { + total.imaginary *= part.real; + } else { + if (!firstreal) { + total = part; + firstreal++; } else { - //Add the value returned to total, and update number. - total += [number floatValue]; - number = [NSNumber numberWithFloat:total]; + total.real *= part.real; } } } - break; - case GIDAOperatorTimes: - //Times operator. (Make total 1.0, to be able to do the mutliplications. - if (i == 0) { - total = 1.0; - } - - //Try to format the split string. - temp = [formatter numberFromString:[split objectAtIndex:i]]; - if (temp) { - //It is a number, then multiply it to total, and update number - total *= [temp floatValue]; - number = [NSNumber numberWithFloat:total]; + } + + if (firstimag && imagetimes%2 == 0) { + if (!firstreal) { + total.real = (-1 * total.imaginary); } else { - //Not a number but it could still be an operation, try with '/'. - number = [self solveString:[split objectAtIndex:i] andOperator:GIDAOperatorFraction]; - if (!number) { - //Still not a number, abort!! - i = [split count]; - } else { - //It was a fraction so we can mutiply the value returned and update number. - total *= [number floatValue]; - number = [NSNumber numberWithFloat:total]; - } + total.real *= (-1 * total.imaginary); } - break; - case GIDAOperatorFraction: - //Fraction operation. - //Check if the split is a number. - temp = [formatter numberFromString:[split objectAtIndex:i]]; - if (temp) { - //It is a number. - //If it is the begining of the split then use the number as total, and update number. - if (i == 0) { - total = [temp floatValue]; - number = [NSNumber numberWithFloat:total]; - } else { - //It is not the first value of the array, and the division number is different than zero. - //(Division by 0 are considered not valid) - if ([temp floatValue] != 0.0) { - //Divide the total, and update number. - total /= [temp floatValue]; - number = [NSNumber numberWithFloat:total]; + total.imaginary = 0; + } + return total; + } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; + } +} + ++(ComplexObject *)divisionAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d|[-.i√])*" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + int position = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + ComplexObject *root = [self rootAndRegEx:sub]; + [splitString addObject:root]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:[string doubleValue] andImaginary:0]; + return complex; + } else { + position = range.location + range.length + 1; + if (position < [string length]) { + [splitString addObject:[string substringWithRange:NSMakeRange(position, [string length]-position)]]; + } + + ComplexObject *total; + int i = 0; + for (ComplexObject *part in splitString) { + if (i == 0) { + total = part; + i++; + } else { + if (total.imaginary != 0) { + if (part.imaginary != 0) { + total.imaginary /= part.imaginary; } else { - //Terminate iteration and number is nil, to represent a nonvalid result. - i = [split count]; - number = nil; + total.imaginary /= part.real; } + } else { + total.real /= part.real; } - } else { - //Not a number so lets stop and say number is nil. - i = [split count]; - number = nil; + //total.imaginary /= part.imaginary; } - break; - default: - //Anyother operator just stop. - i = [split count]; - number = nil; - break; + } + return total; } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; } +} + ++(ComplexObject *)rootAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"√((\\d|[-.i])*)" + options:NSRegularExpressionCaseInsensitive + error:&error]; - [formatter release]; - //Return the number. It could be an NSNumber or nil. - return number; + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + range.length -= 1; + range.location += 1; + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + ComplexObject *com = [self complexAndRegEx:sub]; + [splitString addObject:com]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [self complexAndRegEx:string]; + + return complex; + } else { + ComplexObject *total = nil; + for (ComplexObject *part in splitString) { + total = part; + } + /* + ComplexObject *complex = nil; + if (total.imaginary != 0) { + double real = total.imaginary * cos(0.785398163); + double imag = total.imaginary * sin(0.785398163); + complex = [[ComplexObject alloc] initWithReal:real + andImaginary:imag]; + } else { + if (total.real < 0) { + complex = [[ComplexObject alloc] initWithReal:0 andImaginary:sqrt(fabsf(total.real))]; + } else { + complex = [[ComplexObject alloc] initWithReal:sqrt(total.real) andImaginary:0]; + } + }*/ + [total squareRoot]; + return total; + } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; + } } ++(ComplexObject *)complexAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"((\\d|[-.])*)i" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + range.length -= 1; + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + [splitString addObject:sub]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:[string doubleValue] andImaginary:0]; + + return complex; + } else { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:0 + andImaginary:[[splitString objectAtIndex:0] doubleValue]]; + return complex; + } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; + } +} //Solve the NSString. //With a string, solve its content if it is an operation if it is not a valid operation returns nil. -+(NSNumber *)solveString:(NSString *)string { - NSNumber *result = nil; ++(ComplexObject *)solveString:(NSString *)string { + ComplexObject *result = nil; //Check if it is a valid expression based on parenthesis. - //If it was the same open as close parentheses it is considered valid. + //If it has the same number of open as of close parentheses, it is considered valid. if ([self openParenthesesFor:string toLocation:[string length]] == 0) { //Fix the string. String might need some help to process eg. )( should be )*( string = [self fixString:string]; - - //Check if the string has parentheses - if ([self hasParentheses:string]) { - //Try to obtain a special array with the middle object is the string to process - //When done, concatenate all other objects and try to solve recursively. - NSMutableArray *parentheses = [NSMutableArray arrayWithArray:[self splitString:string byOperator:GIDAOperatorOpenParentheses]]; - if (parentheses) { - NSNumber *par = [self solveString:[parentheses objectAtIndex:1]]; - if (par) { - [parentheses setObject:[par stringValue] atIndexedSubscript:1]; - string = [parentheses componentsJoinedByString:@""]; - result = [self solveString:string]; - } - } - } else { - //Start solving based on +, then, * then /. - result = [self solveString:string andOperator:GIDAOperatorPlus]; - } + result = [self parenthesisAndRegEx:string]; } return result; diff --git a/Demo/Demo/GIDACalculateTextField.h b/Demo/Demo/GIDACalculateTextField.h new file mode 100644 index 0000000..a9dc0a9 --- /dev/null +++ b/Demo/Demo/GIDACalculateTextField.h @@ -0,0 +1,13 @@ +// +// GIDACalculateTextField.h +// Demo +// +// Created by Alejandro Paredes Alva on 9/25/13. +// Copyright (c) 2013 Alejandro Paredes Alva. All rights reserved. +// + +#import + +@interface GIDACalculateTextField : UITextField + +@end diff --git a/Demo/Demo/GIDACalculateTextField.m b/Demo/Demo/GIDACalculateTextField.m new file mode 100644 index 0000000..080a58f --- /dev/null +++ b/Demo/Demo/GIDACalculateTextField.m @@ -0,0 +1,88 @@ +// +// GIDACalculateTextField.m +// Demo +// +// Created by Alejandro Paredes Alva on 9/25/13. +// Copyright (c) 2013 Alejandro Paredes Alva. All rights reserved. +// + +#import "GIDACalculateTextField.h" +#import "GIDACalculateString.h" + +@interface GIDACalculateTextField () +@property (nonatomic, strong) UIToolbar *kbtb; +@end + +@implementation GIDACalculateTextField + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + + [self initialize]; + } + return self; +} + +-(id)init { + if (self = [super init]) { + [self initialize]; + } + return self; +} + +-(void)initialize { + //Attributes for textfields that are not the solution column + self.borderStyle=UITextBorderStyleRoundedRect; + self.adjustsFontSizeToFitWidth = YES; + [self setFont:[UIFont systemFontOfSize:20]]; + [self setTextColor:[UIColor blackColor]]; + self.keyboardType=UIKeyboardTypeDecimalPad; + + //Attributes for textfields that are not the solution column + UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + UIBarButtonItem *plus = [[UIBarButtonItem alloc] initWithTitle:@"+" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *minus = [[UIBarButtonItem alloc] initWithTitle:@"-" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *times = [[UIBarButtonItem alloc] initWithTitle:@"*" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *fraction = [[UIBarButtonItem alloc] initWithTitle:@"/" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *root = [[UIBarButtonItem alloc] initWithTitle:@"√" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *imaginary = [[UIBarButtonItem alloc] initWithTitle:@"i" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *openPar = [[UIBarButtonItem alloc] initWithTitle:@"(" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *closePar = [[UIBarButtonItem alloc] initWithTitle:@")" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *betweenArrowsSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; + + [betweenArrowsSpace setWidth:18]; + UIBarButtonItem *betweenSignAndArrowSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; + [betweenSignAndArrowSpace setWidth:25]; + + _kbtb = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 30)]; + [_kbtb setBarStyle:UIBarStyleBlackTranslucent]; + [_kbtb setItems:[NSArray arrayWithObjects: space, plus, space, minus, space, times, space, fraction, space, root, space, imaginary, space, openPar, space, closePar, space, nil]]; + + if ([[[UIDevice currentDevice] systemVersion] floatValue] >=7.0) { + [_kbtb setTintColor:[UIColor whiteColor]]; + } + + self.inputAccessoryView = _kbtb; + self.keyboardAppearance = UIKeyboardAppearanceAlert; + self.returnKeyType = UIReturnKeyNext; + self.delegate = self; +} + +-(void)option:(id)sender { + UITextRange *selectedRange = [self selectedTextRange]; + int pos = [self offsetFromPosition:self.endOfDocument toPosition:selectedRange.start]; + int length = [[self text] length]; + NSRange range = NSMakeRange(length+pos, 0); + + if ([GIDACalculateString usingThis:[self text] addThis:[sender title] here:range]) + [self setText:[GIDACalculateString stringFrom:[self text] withThis:[sender title] here:range]]; +} + +-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { + return [GIDACalculateString usingThis:[textField text] addThis:string here:range]; +} + +@end diff --git a/Demo/Demo/ViewController.m b/Demo/Demo/ViewController.m index ce976ac..f70caca 100644 --- a/Demo/Demo/ViewController.m +++ b/Demo/Demo/ViewController.m @@ -7,57 +7,21 @@ // #import "ViewController.h" +#import "GIDACalculateTextField.h" @interface ViewController () -@property (retain, nonatomic) IBOutlet UIButton *solveButton; -@property (retain, nonatomic) IBOutlet UITextField *textField; -@property (retain, nonatomic) IBOutlet UILabel *solutionLabel; +@property (strong, nonatomic) IBOutlet UIButton *solveButton; +@property (strong, nonatomic) GIDACalculateTextField *textField; +@property (strong, nonatomic) IBOutlet UILabel *solutionLabel; -(IBAction)solver:(id)sender; @end @implementation ViewController -@synthesize textField = _textField; -@synthesize solutionLabel = _solutionLabel; -- (void)viewDidLoad -{ + +- (void)viewDidLoad { [super viewDidLoad]; - - //Attributes for textfields that are not the solution column - _textField.borderStyle=UITextBorderStyleRoundedRect; - _textField.adjustsFontSizeToFitWidth=YES; - _textField.font=[UIFont fontWithName:@"CourierNewPS-BoldMT" size:20]; - _textField.textColor=[UIColor blackColor]; - _textField.keyboardType=UIKeyboardTypeDecimalPad; - - //Attributes for textfields that are not the solution column - UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - UIBarButtonItem *plus = [[UIBarButtonItem alloc] initWithTitle:@"+" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; - UIBarButtonItem *minus = [[UIBarButtonItem alloc] initWithTitle:@"-" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; - UIBarButtonItem *times = [[UIBarButtonItem alloc] initWithTitle:@"*" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; - UIBarButtonItem *fraction = [[UIBarButtonItem alloc] initWithTitle:@"/" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; - UIBarButtonItem *openPar = [[UIBarButtonItem alloc] initWithTitle:@"(" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; - UIBarButtonItem *closePar = [[UIBarButtonItem alloc] initWithTitle:@")" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; - UIBarButtonItem *betweenArrowsSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; - [betweenArrowsSpace setWidth:18]; - UIBarButtonItem *betweenSignAndArrowSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; - [betweenSignAndArrowSpace setWidth:25]; - - UIToolbar *kbtb = [[[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 30)] autorelease]; - [kbtb setBarStyle:UIBarStyleBlackTranslucent]; - [kbtb setItems:[NSArray arrayWithObjects: space, plus, space, minus, space, times, space, fraction, space, openPar, space, closePar, space, nil]]; - - [space release]; - [plus release]; - [openPar release]; - [closePar release]; - - [betweenArrowsSpace release]; - [betweenSignAndArrowSpace release]; - - _textField.inputAccessoryView = kbtb; - _textField.keyboardAppearance = UIKeyboardAppearanceAlert; - _textField.returnKeyType = UIReturnKeyNext; - _textField.delegate = self; + _textField = [[GIDACalculateTextField alloc] initWithFrame:CGRectMake(20, 30, 280, 30)]; + [self.view addSubview:_textField]; } - (void)didReceiveMemoryWarning @@ -67,20 +31,6 @@ - (void)didReceiveMemoryWarning } --(void)option:(id)sender { - UITextRange *selectedRange = [_textField selectedTextRange]; - int pos = [_textField offsetFromPosition:_textField.endOfDocument toPosition:selectedRange.start]; - int length = [[_textField text] length]; - NSRange range = NSMakeRange(length+pos, 0); - - if ([GIDACalculateString usingThis:[_textField text] addThis:[sender title] here:range]) - [_textField setText:[GIDACalculateString stringFrom:[_textField text] withThis:[sender title] here:range]]; -} - --(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { - return [GIDACalculateString usingThis:[textField text] addThis:string here:range]; -} - -(IBAction)solver:(id)sender { NSNumber *solved = [GIDACalculateString solveString:[_textField text]]; if (solved) { @@ -90,10 +40,4 @@ -(IBAction)solver:(id)sender { } NSLog(@"Solution: %@", [solved stringValue]); } -- (void)dealloc { - [_textField release]; - [_solveButton release]; - [_solutionLabel release]; - [super dealloc]; -} @end diff --git a/Demo/Demo/en.lproj/ViewController.xib b/Demo/Demo/en.lproj/ViewController.xib index f1fe873..4f28b26 100644 --- a/Demo/Demo/en.lproj/ViewController.xib +++ b/Demo/Demo/en.lproj/ViewController.xib @@ -1,587 +1,54 @@ - - - - 1552 - 12C3006 - 3084 - 1187.34 - 625.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 2083 - - - IBNSLayoutConstraint - IBProxyObject - IBUIButton - IBUILabel - IBUITextField - IBUIView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 292 - {{20, 20}, {280, 30}} - - - _NS:9 - NO - YES - IBCocoaTouchFramework - 0 - - 3 - - 3 - MAA - - 2 - - - YES - 17 - - 8 - 1 - IBCocoaTouchFramework - - - 1 - 14 - - - Helvetica - 14 - 16 - - - - - 292 - {{235, 58}, {65, 44}} - - - _NS:9 - NO - IBCocoaTouchFramework - 0 - 0 - 1 - Solve - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - - 292 - {{20, 58}, {207, 43}} - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - - - 1 - MCAwIDAAA - darkTextColor - - - 0 - 9 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - {{0, 20}, {320, 548}} - - - - - 3 - MC43NQA - - - NO - - - IBUIScreenMetrics - - YES - - - - - - {320, 568} - {568, 320} - - - IBCocoaTouchFramework - Retina 4 Full Screen - 2 - - IBCocoaTouchFramework - - - - - - - view - - - - 7 - - - - textField - - - - 25 - - - - solveButton - - - - 29 - - - - solutionLabel - - - - 43 - - - - delegate - - - - 14 - - - - solver: - - - 7 - - 30 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 6 - - - - - - 4 - 0 - - 4 - 1 - - 0.0 - - 1000 - - 6 - 24 - 2 - - - - 5 - 0 - - 6 - 1 - - 8 - - 1000 - - 6 - 24 - 3 - - - - 3 - 0 - - 4 - 1 - - 8 - - 1000 - - 6 - 24 - 3 - - - - 6 - 0 - - 6 - 1 - - 20 - - 1000 - - 8 - 29 - 3 - - - - 3 - 0 - - 4 - 1 - - 8 - - 1000 - - 6 - 24 - 3 - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - - 8 - 29 - 3 - - - - 6 - 0 - - 6 - 1 - - 20 - - 1000 - - 8 - 29 - 3 - - - - 3 - 0 - - 3 - 1 - - 20 - - 1000 - - 8 - 29 - 3 - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - - 8 - 29 - 3 - - - - - - - - 8 - - - - - - 9 - - - - - 10 - - - - - 12 - - - - - 26 - - - - - 7 - 0 - - 0 - 1 - - 65 - - 1000 - - 3 - 9 - 1 - - - - - - 27 - - - - - 28 - - - - - 31 - - - - - 32 - - - - - 33 - - - - - 34 - - - - - 35 - - - - - 36 - - - - - - - ViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - - - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 43 - - - - - NSLayoutConstraint - NSObject - - IBProjectSource - ./Classes/NSLayoutConstraint.h - - - - ViewController - UIViewController - - solver: - id - - - solver: - - solver: - id - - - - UILabel - UIButton - UITextField - - - - solutionLabel - UILabel - - - solveButton - UIButton - - - textField - UITextField - - - - IBProjectSource - ./Classes/ViewController.h - - - - - 0 - IBCocoaTouchFramework - YES - 3 - YES - 2083 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/GIDACalculateString.h b/GIDACalculateString.h index d98916c..88b6580 100644 --- a/GIDACalculateString.h +++ b/GIDACalculateString.h @@ -19,3 +19,9 @@ +(NSNumber *)solveString:(NSString *)string; @end + +@interface ComplexObject : NSObject +@property (nonatomic) double real; +@property (nonatomic) double imaginary; +-(NSString *)stringValue; +@end \ No newline at end of file diff --git a/GIDACalculateString.m b/GIDACalculateString.m index 74f7d8f..5b799bb 100644 --- a/GIDACalculateString.m +++ b/GIDACalculateString.m @@ -7,33 +7,129 @@ // #import "GIDACalculateString.h" +#import enum { - GIDAOperatorNone = 0, - GIDAOperatorOpenParentheses = 1, - GIDAOperatorCloseParentheses = 2, - GIDAOperatorFraction = 3, - GIDAOperatorTimes = 4, - GIDAOperatorPlus = 5, - GIDAOperatorMinus = 6 + GIDAOperatorNone, + GIDAOperatorOpenParentheses, + GIDAOperatorCloseParentheses, + GIDAOperatorFraction, + GIDAOperatorTimes, + GIDAOperatorPlus, + GIDAOperatorMinus, + GIDAOperatorRoot }; typedef NSUInteger GIDAOperator; -@interface GIDACalculateString () +@interface ComplexObject () +@property (nonatomic) double radius; +@property (nonatomic) double angle; +@end + +@implementation ComplexObject +-(id)initWithReal:(double)r andImaginary:(double)i { + self = [super init]; + if (self) { + _real = r; + _imaginary = i; + _radius = sqrt(pow(r,2)+pow(i,2)); + if (_real != 0) { + if (_imaginary == 0) { + _angle = 0; + } else { + _angle = asin(i/_radius); + } + } else { + if (_imaginary != 0) { + _angle = 90.0; + } else { + _angle = 0.0; + } + } + + } + return self; +} +-(void)setReal:(double)real { + _real = real; + _radius = sqrt(pow(_real,2)+pow(_imaginary,2)); + if (_real != 0) { + if (_imaginary == 0) { + _angle = 0; + } else { + _angle = asin(_imaginary/_radius); + } + } else { + if (_imaginary != 0) { + _angle = 90.0; + } else { + _angle = 0.0; + } + } +} +-(void)setImaginary:(double)imaginary { + _imaginary = imaginary; + _radius = sqrt(pow(_real,2)+pow(_imaginary,2)); + if (_real != 0) { + if (_imaginary == 0) { + _angle = 0; + } else { + _angle = asin(_imaginary/_radius); + } + } else { + if (_imaginary != 0) { + _angle = 90.0; + } else { + _angle = 0.0; + } + } +} +-(void)squareRoot { + if (_real < 0) { + _angle = 90.0; + } else { + _angle = _angle / 2.0; + } + + _radius = sqrt(_radius); + double rad = _angle * M_PI / 180.0; + _real = _radius * cos(rad); + if (_angle == 90.0) { + _real = 0; + } + + _imaginary = _radius * sin(rad); + if (_imaginary == 0 || _imaginary == -0) { + _imaginary = 0; + } + NSLog(@"%f",_angle); +} +-(NSString *)stringValue{ + if ((_real > 0 || _real < -0) && _imaginary != 0 ) { + return [NSString stringWithFormat:@"%f+%fi",self.real, self.imaginary]; + } + if (_real == 0 && _imaginary != 0) { + return [NSString stringWithFormat:@"%fi", self.imaginary]; + } + if (_real != 0 && _imaginary == 0) { + return [NSString stringWithFormat:@"%f", self.real]; + } + return @"0"; +} + +@end + +@interface GIDACalculateString () +(BOOL)checkFor:(char)character inThis:(NSString *)string fromThis:(int)position whereThisAre:(NSCharacterSet *)notAllowed andThisHelps:(NSCharacterSet *)toStop; +(BOOL)checkThis:(NSString *)string atThis:(int)position ifLeftDoesNotHave:(NSCharacterSet *)leftCheck norRightHas:(NSCharacterSet *)rightCheck allowFirst:(BOOL)first; +(int)openParenthesesFor:(NSString *)string toLocation:(int)position; +(NSString *)fixString:(NSString *)string; -+(NSNumber *)solveString:(NSString *)string andOperator:(GIDAOperator)operator; -+(NSArray *)splitString:(NSString *)string byOperator:(GIDAOperator)operator; -+(NSArray *)splitFirstParentheses:(NSString *)string; @end @implementation GIDACalculateString - //String appending newString to String. +(NSString *)stringFrom:(NSString *)string withThis:(NSString *)newString { return [string stringByAppendingString:newString]; @@ -181,7 +277,7 @@ +(BOOL)usingThis:(NSString *)string addThis:(NSString *)newString here:(NSRange) //If its the first character to input, check if it is an allowed character. //Allowed characters as first character of input are '.', '-', '(' and numbers from 0 to 9. if ([string length] == 0 || range.location == 0) { - if ([newString characterAtIndex:0] == '.' || [newString characterAtIndex:0] == '-' || [newString characterAtIndex:0] == '(' || ([newString characterAtIndex:0] >= '0' && [newString characterAtIndex:0] <= '9')) { + if ([newString characterAtIndex:0] == '.' || [newString characterAtIndex:0] == '-' || [newString characterAtIndex:0] == '(' || ([newString characterAtIndex:0] >= '0' && [newString characterAtIndex:0] <= '9')) { success = YES; } else { success = NO; @@ -208,7 +304,7 @@ +(BOOL)usingThis:(NSString *)string addThis:(NSString *)newString here:(NSRange) success = [self checkThis:string atThis:range.location ifLeftDoesNotHave:left norRightHas:right allowFirst:NO]; break; case '-': - //The user is not allowed to put a '+' sign when on the left there is a '-'. + //The user is not allowed to put a '-' sign when on the left there is a '-'. //To the right of a '-' sign there can not be a ')', '+', '-', '*', or '/'. left = [NSCharacterSet characterSetWithCharactersInString:@"-"]; right = [NSCharacterSet characterSetWithCharactersInString:@"+-*/)"]; @@ -272,8 +368,12 @@ +(NSString *)fixString:(NSString *)string { [mutable replaceOccurrencesOfString:@"(-" withString:@"OM" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"*-" withString:@"TM" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"/-" withString:@"FM" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + [mutable replaceOccurrencesOfString:@"√-" withString:@"NR" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"+-" withString:@"PM" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + [mutable replaceOccurrencesOfString:@"-" withString:@"+-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + + [mutable replaceOccurrencesOfString:@"NR" withString:@"√-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"MM" withString:@"+" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"PM" withString:@"+-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"FM" withString:@"/-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; @@ -281,235 +381,409 @@ +(NSString *)fixString:(NSString *)string { [mutable replaceOccurrencesOfString:@"OM" withString:@"(-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"CM" withString:@")+-" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; [mutable replaceOccurrencesOfString:@"BM" withString:@"-1*(" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; - [mutable replaceOccurrencesOfString:@"CO" withString:@")*(" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; + [mutable replaceOccurrencesOfString:@"CO" withString:@")*(" options:NSLiteralSearch range:NSMakeRange(0, [string length])]; return mutable; } -//Split in string in 3 parts. -//Before the first parentheses -//The parentheses, between open and close. -//After the parentheses. -//If all string is the parentheses then it is put in the middle and empty trings on the sides. -+(NSArray *)splitFirstParentheses:(NSString *)string { - int i = 0; - NSArray *parentheses = nil; - - //Look for the first '(' - for (i = 0; i < [string length]; i++) { - if ([string characterAtIndex:i] == '(') { - break; - } - } - NSString *pre = [string substringToIndex:i]; ++(ComplexObject *)parenthesisAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; - //Did it find a '(' - if (i == [string length]) { - //Did not find a '(', put string in the middle. - parentheses = [NSArray arrayWithObjects:@"",pre, @"", nil]; - } else { - //Did find a '('. - //If the there is a number before '(', then append to pre a '*'. (As it is a simplification) - if (i != 0) { - if ([string characterAtIndex:i-1] >= '0' && [string characterAtIndex:i-1] <= '9') { - pre = [pre stringByAppendingString:@"*"]; + regex = [NSRegularExpression regularExpressionWithPattern:@"(√)(-*(\\d|[.i])+)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + string = [regex stringByReplacingMatchesInString:string + options:0 + range:NSMakeRange(0, [string length]) + withTemplate:@"√($2)"]; + + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d)(√)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + string = [regex stringByReplacingMatchesInString:string + options:0 + range:NSMakeRange(0, [string length]) + withTemplate:@"$1*$2"]; + + + + regex = [NSRegularExpression regularExpressionWithPattern:@"\\(((\\d|[+-/*√i.])*)\\)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + int position = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; } - } - //par is string where the parentheses is. (without the parentheses) - NSString *par = [string substringFromIndex:i+1]; - - //Look for the close parentheses. Use open in case there are subparentheses inside. - int open = 0; - for (i = 0; i < [par length]; i++) { - if ([par characterAtIndex:i] == '('){ - open ++; - } else { - - if ([par characterAtIndex:i] == ')') { - if (open == 0) { - break; - } else { - open --; - } - } + + range = result.range; + + [splitString addObject:[string substringWithRange:NSMakeRange(position, (range.location)-position)]]; + position = range.location + range.length; + range.length -= 2; + range.location += 1; + NSString *sub = [string substringWithRange:range]; + ComplexObject *numb = [self plusAndRegEx:sub]; + if (!numb) { + return nil; } + [splitString addObject:numb]; + i++; } - - NSString *post = @""; - //If the last character of par is ) then remove it and have post be "". - //If it is not. Cut the string and put the ending part in post. - if (i < [par length] - 1){ - post = [par substringFromIndex:i+1]; - if ([post characterAtIndex:0] >= '0' && [post characterAtIndex:0] <= '9') { - post = [@"*" stringByAppendingString:post]; + if (!i) { + return [self plusAndRegEx:string]; + } else { + position = range.location + range.length + 1; + [splitString addObject:[string substringWithRange:NSMakeRange(position, [string length]-position)]]; + for (int i = 0; i < [splitString count]; i++) { + if ([[splitString objectAtIndex:i] isKindOfClass:[ComplexObject class]]) { + + ComplexObject *complex = (ComplexObject *)[splitString objectAtIndex:i]; + NSString *complexString = [complex stringValue]; + + [splitString setObject:complexString atIndexedSubscript:i]; + } } + return [self parenthesisAndRegEx:[splitString componentsJoinedByString:@""]]; + } - par = [par substringToIndex:i]; - - parentheses = [NSArray arrayWithObjects:pre, par, post, nil]; + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; } - return parentheses; } -//Split a string based on its GIDAOperator. -//Only exception is parentheses and minus. -//Minus does not require spliting as it is considered a negative adition. -//For parentheses call splitFirstPArentheses. -+(NSArray *)splitString:(NSString *)string byOperator:(GIDAOperator)operator { - NSArray *split = nil; - switch (operator) { - case GIDAOperatorOpenParentheses: - split = [self splitFirstParentheses:string]; - break; - case GIDAOperatorPlus: - split = [string componentsSeparatedByString:@"+"]; - break; - case GIDAOperatorTimes: - split = [string componentsSeparatedByString:@"*"]; - break; - case GIDAOperatorFraction: - split = [string componentsSeparatedByString:@"/"]; - break; - default: - break; ++(ComplexObject *)plusAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d|[-i*√/.])*" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + int position = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + + ComplexObject *times = [self timesAndRegEx:sub]; + [splitString addObject:times]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:[string doubleValue] andImaginary:0]; + return complex; + } else { + position = range.location + range.length + 1; + if (position < [string length]) { + [splitString addObject:[string substringWithRange:NSMakeRange(position, [string length]-position)]]; + } + ComplexObject *total = [[ComplexObject alloc] initWithReal:0 andImaginary:0]; + for (ComplexObject *part in splitString) { + total.real += part.real; + total.imaginary += part.imaginary; + } + return total; + } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; } - return split; + } -//Solve string based on operator. -+(NSNumber *)solveString:(NSString *)string andOperator:(GIDAOperator)operator { - float total = 0; - NSNumber *number = nil; - NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - NSNumber *temp = nil; - - //Split the string based on the GIDAOperator. - NSArray *split = [self splitString:string byOperator:operator]; - - //Go through the split string. - for (int i = 0; i < [split count]; i++) { - switch (operator) { - case GIDAOperatorPlus: - //Plus operation. - if (i == 0 && [[split objectAtIndex:i] isEqualToString:@""]){ - } else { - //Try to format to a number. - temp = [formatter numberFromString:[split objectAtIndex:i]]; - if (temp) { - //If it was a number add it to the total, and update number. - total += [temp floatValue]; - number = [NSNumber numberWithFloat:total]; ++(ComplexObject *)timesAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d|[-/i.√])*" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + int position = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + ComplexObject *times = [self divisionAndRegEx:sub]; + [splitString addObject:times]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:[string doubleValue] andImaginary:0]; + return complex; + } else { + position = range.location + range.length + 1; + if (position < [string length]) { + [splitString addObject:[string substringWithRange:NSMakeRange(position, [string length]-position)]]; + } + int firstreal = 0; + int firstimag = 0; + ComplexObject *total = [[ComplexObject alloc] initWithReal:0 andImaginary:0]; + int imagetimes = 0; + + for (ComplexObject *part in splitString) { + if (part.imaginary != 0) { + if (!firstimag){ + firstimag++; + total = part; } else { - //If not a number maybe it has '*' or '/'. So try with '*' - number = [self solveString:[split objectAtIndex:i] andOperator:GIDAOperatorTimes]; - if (!number) { - //Not a number then abort - i = [split count]; + total.imaginary *= part.imaginary; + } + imagetimes++; + } else { + if (firstimag) { + total.imaginary *= part.real; + } else { + if (!firstreal) { + total = part; + firstreal++; } else { - //Add the value returned to total, and update number. - total += [number floatValue]; - number = [NSNumber numberWithFloat:total]; + total.real *= part.real; } } } - break; - case GIDAOperatorTimes: - //Times operator. (Make total 1.0, to be able to do the mutliplications. - if (i == 0) { - total = 1.0; - } - - //Try to format the split string. - temp = [formatter numberFromString:[split objectAtIndex:i]]; - if (temp) { - //It is a number, then multiply it to total, and update number - total *= [temp floatValue]; - number = [NSNumber numberWithFloat:total]; + } + + if (firstimag && imagetimes%2 == 0) { + if (!firstreal) { + total.real = (-1 * total.imaginary); } else { - //Not a number but it could still be an operation, try with '/'. - number = [self solveString:[split objectAtIndex:i] andOperator:GIDAOperatorFraction]; - if (!number) { - //Still not a number, abort!! - i = [split count]; - } else { - //It was a fraction so we can mutiply the value returned and update number. - total *= [number floatValue]; - number = [NSNumber numberWithFloat:total]; - } + total.real *= (-1 * total.imaginary); } - break; - case GIDAOperatorFraction: - //Fraction operation. - //Check if the split is a number. - temp = [formatter numberFromString:[split objectAtIndex:i]]; - if (temp) { - //It is a number. - //If it is the begining of the split then use the number as total, and update number. - if (i == 0) { - total = [temp floatValue]; - number = [NSNumber numberWithFloat:total]; - } else { - //It is not the first value of the array, and the division number is different than zero. - //(Division by 0 are considered not valid) - if ([temp floatValue] != 0.0) { - //Divide the total, and update number. - total /= [temp floatValue]; - number = [NSNumber numberWithFloat:total]; + total.imaginary = 0; + } + return total; + } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; + } +} + ++(ComplexObject *)divisionAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d|[-.i√])*" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + int position = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + ComplexObject *root = [self rootAndRegEx:sub]; + [splitString addObject:root]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:[string doubleValue] andImaginary:0]; + return complex; + } else { + position = range.location + range.length + 1; + if (position < [string length]) { + [splitString addObject:[string substringWithRange:NSMakeRange(position, [string length]-position)]]; + } + + ComplexObject *total; + int i = 0; + for (ComplexObject *part in splitString) { + if (i == 0) { + total = part; + i++; + } else { + if (total.imaginary != 0) { + if (part.imaginary != 0) { + total.imaginary /= part.imaginary; } else { - //Terminate iteration and number is nil, to represent a nonvalid result. - i = [split count]; - number = nil; + total.imaginary /= part.real; } + } else { + total.real /= part.real; } - } else { - //Not a number so lets stop and say number is nil. - i = [split count]; - number = nil; + //total.imaginary /= part.imaginary; } - break; - default: - //Anyother operator just stop. - i = [split count]; - number = nil; - break; + } + return total; } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; } +} + ++(ComplexObject *)rootAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"√((\\d|[-.i])*)" + options:NSRegularExpressionCaseInsensitive + error:&error]; - [formatter release]; - //Return the number. It could be an NSNumber or nil. - return number; + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + range.length -= 1; + range.location += 1; + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + ComplexObject *com = [self complexAndRegEx:sub]; + [splitString addObject:com]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [self complexAndRegEx:string]; + + return complex; + } else { + ComplexObject *total = nil; + for (ComplexObject *part in splitString) { + total = part; + } + /* + ComplexObject *complex = nil; + if (total.imaginary != 0) { + double real = total.imaginary * cos(0.785398163); + double imag = total.imaginary * sin(0.785398163); + complex = [[ComplexObject alloc] initWithReal:real + andImaginary:imag]; + } else { + if (total.real < 0) { + complex = [[ComplexObject alloc] initWithReal:0 andImaginary:sqrt(fabsf(total.real))]; + } else { + complex = [[ComplexObject alloc] initWithReal:sqrt(total.real) andImaginary:0]; + } + }*/ + [total squareRoot]; + return total; + } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; + } } ++(ComplexObject *)complexAndRegEx:(NSString *)string { + NSError *error = nil; + NSRegularExpression *regex = nil; + + regex = [NSRegularExpression regularExpressionWithPattern:@"((\\d|[-.])*)i" + options:NSRegularExpressionCaseInsensitive + error:&error]; + + NSRange textRange = NSMakeRange(0, string.length); + NSArray *matches = [regex matchesInString:string options:NSMatchingReportCompletion range:textRange]; + + NSMutableArray *splitString = nil; + if (matches) { + int i = 0; + NSRange range ; + for (NSTextCheckingResult *result in matches) { + if (!splitString) { + splitString = [NSMutableArray array]; + } + + range = result.range; + range.length -= 1; + if (range.length > 0) { + NSString *sub = [string substringWithRange:range]; + [splitString addObject:sub]; + } + + i++; + } + if (!i) { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:[string doubleValue] andImaginary:0]; + + return complex; + } else { + ComplexObject *complex = [[ComplexObject alloc] initWithReal:0 + andImaginary:[[splitString objectAtIndex:0] doubleValue]]; + return complex; + } + } else { + NSLog(@"Error in REGEX: %@",error.description); + return nil; + } +} //Solve the NSString. //With a string, solve its content if it is an operation if it is not a valid operation returns nil. -+(NSNumber *)solveString:(NSString *)string { - NSNumber *result = nil; ++(ComplexObject *)solveString:(NSString *)string { + ComplexObject *result = nil; //Check if it is a valid expression based on parenthesis. - //If it was the same open as close parentheses it is considered valid. + //If it has the same number of open as of close parentheses, it is considered valid. if ([self openParenthesesFor:string toLocation:[string length]] == 0) { //Fix the string. String might need some help to process eg. )( should be )*( string = [self fixString:string]; - - //Check if the string has parentheses - if ([self hasParentheses:string]) { - //Try to obtain a special array with the middle object is the string to process - //When done, concatenate all other objects and try to solve recursively. - NSMutableArray *parentheses = [NSMutableArray arrayWithArray:[self splitString:string byOperator:GIDAOperatorOpenParentheses]]; - if (parentheses) { - NSNumber *par = [self solveString:[parentheses objectAtIndex:1]]; - if (par) { - [parentheses setObject:[par stringValue] atIndexedSubscript:1]; - string = [parentheses componentsJoinedByString:@""]; - result = [self solveString:string]; - } - } - } else { - //Start solving based on +, then, * then /. - result = [self solveString:string andOperator:GIDAOperatorPlus]; - } + result = [self parenthesisAndRegEx:string]; } return result; diff --git a/GIDACalculateTextField.h b/GIDACalculateTextField.h new file mode 100644 index 0000000..a9dc0a9 --- /dev/null +++ b/GIDACalculateTextField.h @@ -0,0 +1,13 @@ +// +// GIDACalculateTextField.h +// Demo +// +// Created by Alejandro Paredes Alva on 9/25/13. +// Copyright (c) 2013 Alejandro Paredes Alva. All rights reserved. +// + +#import + +@interface GIDACalculateTextField : UITextField + +@end diff --git a/GIDACalculateTextField.m b/GIDACalculateTextField.m new file mode 100644 index 0000000..080a58f --- /dev/null +++ b/GIDACalculateTextField.m @@ -0,0 +1,88 @@ +// +// GIDACalculateTextField.m +// Demo +// +// Created by Alejandro Paredes Alva on 9/25/13. +// Copyright (c) 2013 Alejandro Paredes Alva. All rights reserved. +// + +#import "GIDACalculateTextField.h" +#import "GIDACalculateString.h" + +@interface GIDACalculateTextField () +@property (nonatomic, strong) UIToolbar *kbtb; +@end + +@implementation GIDACalculateTextField + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + + [self initialize]; + } + return self; +} + +-(id)init { + if (self = [super init]) { + [self initialize]; + } + return self; +} + +-(void)initialize { + //Attributes for textfields that are not the solution column + self.borderStyle=UITextBorderStyleRoundedRect; + self.adjustsFontSizeToFitWidth = YES; + [self setFont:[UIFont systemFontOfSize:20]]; + [self setTextColor:[UIColor blackColor]]; + self.keyboardType=UIKeyboardTypeDecimalPad; + + //Attributes for textfields that are not the solution column + UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + UIBarButtonItem *plus = [[UIBarButtonItem alloc] initWithTitle:@"+" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *minus = [[UIBarButtonItem alloc] initWithTitle:@"-" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *times = [[UIBarButtonItem alloc] initWithTitle:@"*" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *fraction = [[UIBarButtonItem alloc] initWithTitle:@"/" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *root = [[UIBarButtonItem alloc] initWithTitle:@"√" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *imaginary = [[UIBarButtonItem alloc] initWithTitle:@"i" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *openPar = [[UIBarButtonItem alloc] initWithTitle:@"(" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *closePar = [[UIBarButtonItem alloc] initWithTitle:@")" style:UIBarButtonItemStylePlain target:self action:@selector(option:)]; + UIBarButtonItem *betweenArrowsSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; + + [betweenArrowsSpace setWidth:18]; + UIBarButtonItem *betweenSignAndArrowSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; + [betweenSignAndArrowSpace setWidth:25]; + + _kbtb = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 30)]; + [_kbtb setBarStyle:UIBarStyleBlackTranslucent]; + [_kbtb setItems:[NSArray arrayWithObjects: space, plus, space, minus, space, times, space, fraction, space, root, space, imaginary, space, openPar, space, closePar, space, nil]]; + + if ([[[UIDevice currentDevice] systemVersion] floatValue] >=7.0) { + [_kbtb setTintColor:[UIColor whiteColor]]; + } + + self.inputAccessoryView = _kbtb; + self.keyboardAppearance = UIKeyboardAppearanceAlert; + self.returnKeyType = UIReturnKeyNext; + self.delegate = self; +} + +-(void)option:(id)sender { + UITextRange *selectedRange = [self selectedTextRange]; + int pos = [self offsetFromPosition:self.endOfDocument toPosition:selectedRange.start]; + int length = [[self text] length]; + NSRange range = NSMakeRange(length+pos, 0); + + if ([GIDACalculateString usingThis:[self text] addThis:[sender title] here:range]) + [self setText:[GIDACalculateString stringFrom:[self text] withThis:[sender title] here:range]]; +} + +-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { + return [GIDACalculateString usingThis:[textField text] addThis:string here:range]; +} + +@end