3

I have a UILabel that has a formatted String (formatted for currency), so there is a dollar sign, $21.34.

In the core data entity the attribute is of a type double, I am using an NSDecimalNumber to save to the database.

    self.purchase.name = self.nameTextField.text;
    NSString *string = self.amountLabel.text
    NSDecimalNumber *newAmount = [[NSDecimalNumber alloc] initWithString:string];
    NSLog(@"%@", string); // THIS RETURNS NaN, because of dollar sign i think

    NSManagedObjectContext *context = self.purchase.managedObjectContext;

    NSError *error = nil;
    if (![context save:&error]) 
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

Anyway, I need this to not be NaN, so my thinking is to remove the dollar sign, but i do not know how to do that, or perhaps there is a better way to accomplish my goal.

Scott McKenzie
  • 16,052
  • 8
  • 45
  • 70
iAm
  • 219
  • 3
  • 5
  • 12

7 Answers7

10
    NSString* cleanedString = [costString stringByTrimmingCharactersInSet: [NSCharacterSet symbolCharacterSet]];

Is a lot more robust than the one above (and I think it will handle commas, too)

justin
  • 868
  • 1
  • 5
  • 11
5

OK, so i ended up using this code and it works for me

        NSString *inString = self.amountLabel.text;
    NSMutableString *outString = [NSMutableString stringWithCapacity:inString.length];

    NSScanner *scanner = [NSScanner scannerWithString:inString];
    NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@".0123456789"];

    while ([scanner isAtEnd] == NO)
    {
        NSString *buffer;
        if ([scanner scanCharactersFromSet:numbers intoString:&buffer])
        {
            [outString appendString:buffer];
        }
        else {
            [scanner setScanLocation:([scanner scanLocation] + 1)];
        }

    }
    NSLog(@"%@", outString);
    NSDecimalNumber *amount = [NSDecimalNumber decimalNumberWithString:outString];

    self.purchase.amount = amount;
iAm
  • 219
  • 3
  • 5
  • 12
  • 2
    UGH this is total overkill. You can use an `NSNumberFormatter` to remove the formatting around the string and give it back to you as an `NSNumber`. Your code will also break any time you come across a currency that places the sign to the right of the numbers. An `NSNumberFormatter` would correctly handle it. – Dave DeLong Feb 18 '10 at 16:32
  • 1
    The place of the currency sign does not matter, rather the code is looking for any char that does not match the NSCharacterSet and then removing it from the string if it's not in the set – iAm Feb 19 '10 at 03:40
2

To add to @justin's answer:

[NSCharacterSet symbolCharacterSet]

won't remove commas. So you can combine it with:

stringByReplacingOccurrencesOfString

and use:

    NSString* cleanedString = [[costString stringByReplacingOccurrencesOfString:@"," withString:@""] 
stringByTrimmingCharactersInSet: [NSCharacterSet symbolCharacterSet]];

to get a cleaned number suitable for arithmetic (e.g. £1,005.33 becomes 1005.33)

Leafy
  • 161
  • 1
  • 5
1

Really you should have your value which is a simple number, like a float if dealing in currency. Then you should have a string that represents your value. You could use an NSNumberFormatter to get from the value to the string, like you say you have, but you shouldn't be relying on the string as your only source of that value.

Also, NSDecimalNumber is probably overkill for representing something like currency. NSDecimalNumber is better suited for dealing with numbers in scientific notation.

A simple NSNumber object will be good enough for working with currency, using something like numberWithDouble:.

Jasarien
  • 58,279
  • 31
  • 157
  • 188
  • 2
    Please do not say that NSDecimalNumber is overkill. It is exactly the right thing to use for many applications, especially when dealing with financial data. – Ole Begemann Feb 18 '10 at 16:27
  • From the docs: "NSDecimalNumber, an immutable subclass of NSNumber, provides an object-oriented wrapper for doing base-10 arithmetic. An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127." -- NSNumber is more than sufficient for dealing with financial data. – Jasarien Feb 18 '10 at 17:07
  • A number format in which simple numbers like 0.1 are not representable without possibly introducing rounding errors is not very suitable for many applications dealing with financial data. Floating point is great for many things but accurate financial calculation is not one of them. – Ole Begemann Feb 19 '10 at 03:41
  • 1
    I am sorry, but NSDecimalNumber is the correct type when dealing with Currency, thank you – iAm Feb 19 '10 at 03:41
  • NSNumber is capable of representing numbers far more precise than just 0.1. – Jasarien Feb 19 '10 at 08:07
  • 2
    @Jasarien: yes. But it is not capable of representing many simple numbers exactly (0.1 is one such example). Regardless of the precision of the fp unit. – Ole Begemann Feb 19 '10 at 11:33
  • 1
    I hope you're joking. If it's money, use `NSDecimalNumber`. – Steven Fisher Jul 07 '12 at 01:47
1

If you need to remove the $ sign. why not just do the following before dealing with the number

NSString *newStringValue = [inputString stringByReplacingOccurrencesOfString:@"$" withString:@""];
Sangram Shivankar
  • 3,535
  • 3
  • 26
  • 38
Joo Park
  • 3,115
  • 4
  • 27
  • 31
1

Combining @justin's and @leafy's answer:

[[@"$1,000" stringByReplacingOccurrencesOfString:@"," withString:@""] stringByTrimmingCharactersInSet: [NSCharacterSet symbolCharacterSet]];

This will give you 1000.

Ari
  • 990
  • 12
  • 12
0

Try this:

NSDecimalNumber *newAmount = [[NSDecimalNumber alloc] initWithString:[string substringFromIndex:1]];
willcodejavaforfood
  • 43,223
  • 17
  • 81
  • 111