views:

147

answers:

3

Is there a way to use NSNumberFormatter to get the 'th' 'st' 'nd' 'rd' number endings?

EDIT:

Looks like it does not exist. Here's what I'm using.

+(NSString*)ordinalNumberFormat:(NSInteger)num{
    NSString *ending;

    int ones = num % 10;
    int tens = floor(num / 10);
    tens = tens % 10;
    if(tens == 1){
        ending = @"th";
    }else {
        switch (ones) {
            case 1:
                ending = @"st";
                break;
            case 2:
                ending = @"nd";
                break;
            case 3:
                ending = @"rd";
                break;
            default:
                ending = @"th";
                break;
        }
    }
    return [NSString stringWithFormat:@"%d%@", num, ending];
}

Adapted from nickf's answer here http://stackoverflow.com/questions/69262/is-there-an-easy-way-in-net-to-get-st-nd-rd-and-th-endings-for-numbers

+2  A: 

I'm not aware of this capability. However, it's possible to do this yourself. In English, the ordinal (th, st, nd, rd, etc) has a really simple pattern:

If the number ends with: => Use:

  • 0 => th
  • 1 => st
  • 2 => nd
  • 3 => rd
  • 4 => th
  • 5 => th
  • 6 => th
  • 7 => th
  • 8 => th
  • 9 => th
  • 11 => th
  • 12 => th
  • 13 => th

This will not spell out the word for you, but it will allow you to do something like: "42nd", "1,340,697th", etc.

This gets more complicated if you need it localized.

Dave DeLong
This misses some of the teens. I found the algorithm here:http://stackoverflow.com/questions/69262/is-there-an-easy-way-in-net-to-get-st-nd-rd-and-th-endings-for-numbersJust thought maybe the formatter could handle.
jan
@jan good point about 11, 12, and 13. Those suffixes could easily be special-cased.
Dave DeLong
@Abizern how so? Those are covered by the rules I listed in my answer (*1 => st, *2 => nd, *3 => rd)
Dave DeLong
A: 

The following example demonstrates how to handle any number. It's in c# however it can easily converted to any language.

http://www.bytechaser.com/en/functions/b6yhfyxh78/convert-number-to-ordinal-like-1st-2nd-in-c-sharp.aspx

Alex
+1  A: 

Since the question asked for a number formatter, here's a rough one I made.

//
//  OrdinalNumberFormatter.h
//

#import <Foundation/Foundation.h>


@interface OrdinalNumberFormatter : NSNumberFormatter {

}

@end

and the implementation:

//
//  OrdinalNumberFormatter.m
//

#import "OrdinalNumberFormatter.h"


@implementation OrdinalNumberFormatter

- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error {
    NSInteger integerNumber;
    NSScanner *scanner;
    BOOL isSuccessful = NO;
    NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];

    scanner = [NSScanner scannerWithString:string];
    [scanner setCaseSensitive:NO];
    [scanner setCharactersToBeSkipped:letters];

    if ([scanner scanInteger:&integerNumber]){
        isSuccessful = YES;
        if (anObject) {
            *anObject = [NSNumber numberWithInteger:integerNumber];
        }
    } else {
        if (error) {
            *error = [NSString stringWithFormat:@"Unable to create number from %@", string];
        }
    }

    return isSuccessful;
}

- (NSString *)stringForObjectValue:(id)anObject {
    if (![anObject isKindOfClass:[NSNumber class]]) {
        return nil;
    }

    NSString *strRep = [anObject stringValue];
    NSString *lastDigit = [strRep substringFromIndex:([strRep length]-1)];

    NSString *ordinal;


    if ([strRep isEqualToString:@"11"] || [strRep isEqualToString:@"12"] || [strRep isEqualToString:@"13"]) {
        ordinal = @"th";
    } else if ([lastDigit isEqualToString:@"1"]) {
        ordinal = @"st";
    } else if ([lastDigit isEqualToString:@"2"]) {
        ordinal = @"nd";
    } else if ([lastDigit isEqualToString:@"3"]) {
        ordinal = @"rd";
    } else {
        ordinal = @"th";
    }

    return [NSString stringWithFormat:@"%@%@", strRep, ordinal];
}

@end

Instantiate this as an Interface Builder object and attach the Text Field's formatter outlet to it. For finer control (such as setting maximum and minimum values, you should create an instance of the formatter, set the properties as you wish and attach it to text field using it's setFormatter: method.

You can download an example project [22 kb]

Abizern