1

I've got this basic like script that I need to convert to objective c, it turns big units of money into shortened versions (ie: 1.2m, etc), I've got most of the conversion done, but the biggest problem I'm having is right at the end.

The original basic code is:

; Basic Code

Function ShortCash$(BigNumber)
out$=""


    ; First, grab the length of the number
    L=Len(BigNumber)

    Letter$=""

    ;Next, Do a sweep of the values, and cut them down.
        If l<13 
            out$=(BigNumber/1000000000)

            ; For each figure, out remainder should be divided so that it leaves a 2 digit decimal number..
            remainder=(BigNumber Mod 1000000000)/10000000

            ; And we also want a letter to symbolise our large amounts..
            Letter$="b" ; BILLION!!!!
        EndIf
        If l<10 Then out$=(BigNumber/1000000):remainder=(BigNumber Mod 1000000)/10000:Letter$="m"
        If l<7 Then out$=(BigNumber/1000):remainder=(BigNumber Mod 1000)/10:Letter$="k"
        If l<4 Then out$=BigNumber:remainder=0:Letter$=""

    ;Next, if remainder=0 then we're happy..  ie, £1m is fine, we need no decimal.
    ;But, if the remainder is >0 we'll want a nice rounded 2 decimal number, instead.
    If remainder>0
        out$=out$+"."+Right$("00"+remainder,2) ; Last two numbers..

        ; Additionally, if the rightmost figure is a 0, remove it.
        ; (ie, if the value is 1.50, we don't need the 0)
        If Right$(out$,1)="0" Then out$=Left$(out$,Len(out$)-1)

    EndIf


    ; And throw on our letter, at the end.
    out$=out$+letter$ 

Return out$
End Function

// The following was edited on Thur 5 Aug by Author of post.

I believe I've got it sorted now, I've got the following to work for thousands for the moment, I'm not sure if it will work under all circumstances and would welcome any help/guidance on this. I am aware of the memory issues, I'll sort that out later, its the string manipulation part I am resolving first.

// This goes inside the (IBAction) update method;

    NSNumber *bigNumber = nil;

    if ( [inputField.text length] >0)
    {
        bigNumber = [NSNumber numberWithInt:[inputField.text intValue]];
    }

    int bigNumberAsInt          = [bigNumber intValue];
    NSString *bigNumberAsString = [bigNumber stringValue];
    int bigNumberStrLen         = [bigNumberAsString length];

    NSLog(@"bigNumber = %@", bigNumber);
    //NSLog(@"bigNumberAsString = %@", bigNumberAsString);
    NSLog(@"bigNumberStrLen = %d", bigNumberStrLen);
    NSLog(@"=========");

    // =========

    NSNumberFormatter *nformat = [[[NSNumberFormatter alloc] init] autorelease];

    [nformat setFormatterBehavior:NSNumberFormatterBehavior10_4];
    [nformat setCurrencySymbol:@"$"];
    [nformat setNumberStyle:NSNumberFormatterCurrencyStyle];
    [nformat setMaximumFractionDigits:0];

    NSLog(@"Cash = %@", [nformat stringFromNumber:bigNumber]);

    // =========


    NSString *output = [[NSString alloc] init]; 
    NSString *letter;


    // ==========

    // Anything less than 1m represent with a k
    if (bigNumberStrLen < 7) 
    {
        letter = @"k";
        int sum = (bigNumberAsInt / 1000);
        int int_remainder = ((bigNumberAsInt % 1000) / 10);

        NSLog(@"Remainder = %d", int_remainder);

        NSString *sumAsString = [NSString stringWithFormat:@"%d", sum];
        NSString *remainderAsString = [NSString stringWithFormat:@"%d", int_remainder];

        NSLog(@"Sum as String = %@", sumAsString);
        NSLog(@"Remainder as String = %@", remainderAsString);

        if (int_remainder >0)
        {
            NSLog(@"Remainder > 0");

            output = [output stringByAppendingString:sumAsString];
            output = [output stringByAppendingString:@"."];
            output = [output stringByAppendingString:remainderAsString];

            NSLog(@"Output = %@", output);

            NSUInteger outputStrLen = [output length];

            NSLog(@"Output strlen = %d", outputStrLen);

            if ([output hasSuffix:@"0"])
            {
                NSLog(@"Has suffix of 0");

                // Remove suffix
                output = [output substringWithRange: NSMakeRange(0, outputStrLen-1)];
            }

        }

        output = [output stringByAppendingString:letter];

        NSLog(@"Final output = %@", output);


    }

This will display 10.2k (if it ends with a 0 suffix) or it will display 10.2x where X is the last number.

Can someone just double check this, or perhaps there's an easier way to do all this. In either case, thanks for your help.

zardon
  • 2,910
  • 6
  • 37
  • 58

2 Answers2

1

Just to improve the solution, a good idea is maybe to subclass the NSNumberFormatter class and override the - (NSString *)stringForObjectValue:(id)anObject method.

Using the code from zardon, I added a statement for the values < 1000 which doesn't format the number.

Here is the code of the method :

/*
    Override the stringForObjectValue method from NSNumberFormatter

    100 -> 100
    1000 -> 1k
    1 000 000 -> 1m
    1 000 000 000 -> 1b
    1 000 000 000 -> 1t
 */
- (NSString *)stringForObjectValue:(id)anObject {

    // If we don't get a NSNumber, we can't create the string
    if (![anObject isKindOfClass:[NSNumber class]]) {
        return nil;
    }

    NSNumberFormatter *nformat = [[NSNumberFormatter alloc] init];

    // Decimal value from the NSObject
    double doubleValue = [anObject doubleValue];

    NSString *stringValue = nil;

    // Abbrevations used
    NSArray *abbrevations = [NSArray arrayWithObjects:@"k", @"m", @"b", @"t", nil] ;

    // If the value is less than 1000, we display directly the value
    if(doubleValue < 1000.0) {
        stringValue = [NSString stringWithFormat: @"%@", [nformat stringFromNumber: [NSNumber numberWithDouble: doubleValue]] ];
    }
    else { // Otherwise we format it as expected
        for (NSString *s in abbrevations) {
            doubleValue /= 1000.0 ;

            if ( doubleValue < 1000.0 ) {

                if ( (long long)doubleValue % (long long) 100 == 0 ) {
                    [nformat setMaximumFractionDigits:0];
                } else {                
                    [nformat setMaximumFractionDigits:2];
                }

                stringValue = [NSString stringWithFormat: @"%@", [nformat stringFromNumber: [NSNumber numberWithDouble: doubleValue]] ];
                NSUInteger stringLen = [stringValue length];

                if ( [stringValue hasSuffix:@".00"] )
                {               
                    // Remove suffix
                    stringValue = [stringValue substringWithRange: NSMakeRange(0, stringLen-3)];            
                } else if ( [stringValue hasSuffix:@".0"] ) {

                    // Remove suffix
                    stringValue = [stringValue substringWithRange: NSMakeRange(0, stringLen-2)];

                } else if ( [stringValue hasSuffix:@"0"] ) {

                    // Remove suffix
                    stringValue = [stringValue substringWithRange: NSMakeRange(0, stringLen-1)];        
                }

                // Add the letter suffix at the end of it
                stringValue = [stringValue stringByAppendingString: s];

                break;
            }   
        }
    }

    [nformat release];

    return stringValue;
}

In the interface we simply add the inheritage statement :

@interface MoneyNumberFormatter : NSNumberFormatter

Hope this helps..

Fabien Demangeat
  • 935
  • 8
  • 12
  • Although I am using the solution I posted earlier, I think your subclassing idea is a really good extension/idea. – zardon May 30 '11 at 20:23
0

.... Okay, with thanks to the author of the Cocoa Tidbits blog, I believe I have a solution which is much more elegant, faster and doesn't require so much coding; it still needs testing, and it also probably requires a little more editing, but it seems to be much better than my original.

I modified the script a little to make it not show any trailing zeros where relevant;

    NSNumberFormatter *nformat = [[NSNumberFormatter alloc] init];
    [nformat setFormatterBehavior:NSNumberFormatterBehavior10_4];
    [nformat setCurrencySymbol:@"$"];
    [nformat setNumberStyle:NSNumberFormatterCurrencyStyle];
    double doubleValue = 10200;
    NSString *stringValue = nil;
    NSArray *abbrevations = [NSArray arrayWithObjects:@"k", @"m", @"b", @"t", nil] ;

    for (NSString *s in abbrevations)
    {

        doubleValue /= 1000.0 ;

        if ( doubleValue < 1000.0 )
        {

            if ( (long long)doubleValue % (long long) 100 == 0 ) {
                [nformat setMaximumFractionDigits:0];
            } else {                
                [nformat setMaximumFractionDigits:2];
            }

            stringValue = [NSString stringWithFormat: @"%@", [nformat stringFromNumber: [NSNumber numberWithDouble: doubleValue]] ];
            NSUInteger stringLen = [stringValue length];

            if ( [stringValue hasSuffix:@".00"] )
            {               
                // Remove suffix
                stringValue = [stringValue substringWithRange: NSMakeRange(0, stringLen-3)];            
            } else if ( [stringValue hasSuffix:@".0"] ) {

                // Remove suffix
                stringValue = [stringValue substringWithRange: NSMakeRange(0, stringLen-2)];

            } else if ( [stringValue hasSuffix:@"0"] ) {

                // Remove suffix
                stringValue = [stringValue substringWithRange: NSMakeRange(0, stringLen-1)];        
            }


            // Add the letter suffix at the end of it
            stringValue = [stringValue stringByAppendingString: s];

            //stringValue = [NSString stringWithFormat: @"%@%@", [nformat stringFromNumber: [NSNumber numberWithDouble: doubleValue]]  , s] ;
            break ;
        }   
    } 

    NSLog(@"Cash = %@", stringValue);
zardon
  • 2,910
  • 6
  • 37
  • 58