6

I'm looking for a way to take a number (say 5 or 207), spell it out, and returns its ordinal form as a string (five or two hundred seven). All I could find was code that takes a number and returns its ordinal suffix (st, nd, rd, th) and the parts of English grammar guides that say you should spell out ordinals.

I'm looking for a way to get a spelled out number with its ordinal suffix (fifth or two hundred seventh).

Tunaki
  • 132,869
  • 46
  • 340
  • 423
Techno Cat
  • 61
  • 5

3 Answers3

10

Update: I came across this answer today, suggesting the use of the use of this library under the MIT-License which also supports a few other languages. Hope this helps someone.

Old Answer:
I coded a script which can this, but only in english:

- (NSString*)getSpelledOutNumber:(NSInteger)num
{
    NSNumber *yourNumber = [NSNumber numberWithInt:(int)num];
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    [formatter setNumberStyle:NSNumberFormatterSpellOutStyle];
    [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en"]];
    return [formatter stringFromNumber:yourNumber];
}

- (NSString*)removeLastCharOfString:(NSString*)aString
{
    return [aString substringToIndex:[aString length]-1];
}

- (NSString*)getSpelledOutOrdinalNumber:(NSInteger)num
{    
    NSString *spelledOutNumber = [self getSpelledOutNumber:num];

    // replace all '-'
    spelledOutNumber = [spelledOutNumber stringByReplacingOccurrencesOfString:@"-"
                                                                   withString:@" "];

    NSArray *numberParts = [spelledOutNumber componentsSeparatedByString:@" "];

    NSMutableString *output = [NSMutableString string];

    NSUInteger numberOfParts = [numberParts count];
    for (int i=0; i<numberOfParts; i++) {
        NSString *numberPart = [numberParts objectAtIndex:i];

        if ([numberPart isEqualToString:@"one"])
            [output appendString:@"first"];
        else if([numberPart isEqualToString:@"two"])
            [output appendString:@"second"];
        else if([numberPart isEqualToString:@"three"])
            [output appendString:@"third"];
        else if([numberPart isEqualToString:@"five"])
            [output appendString:@"fifth"];
        else {
            NSUInteger characterCount = [numberPart length];
            unichar lastChar = [numberPart characterAtIndex:characterCount-1];
            if (lastChar == 'y')
            {
                // check if it is the last word
                if (numberOfParts-1 == i)
                { // it is
                    [output appendString:[NSString stringWithFormat:@"%@ieth ", [self removeLastCharOfString:numberPart]]];
                }
                else
                { // it isn't
                    [output appendString:[NSString stringWithFormat:@"%@-", numberPart]];
                }
            }
            else if (lastChar == 't' || lastChar == 'e')
            {
                [output appendString:[NSString stringWithFormat:@"%@th-", [self removeLastCharOfString:numberPart]]];
            }
            else
            {
                [output appendString:[NSString stringWithFormat:@"%@th ", numberPart]];
            }
        }
    }

    // eventually remove last char
    unichar lastChar = [output characterAtIndex:[output length]-1];
    if (lastChar == '-' || lastChar == ' ')
        return [self removeLastCharOfString:output];
    else
        return output;
}

The usage is pretty simple:

NSString *ordinalNumber = [self getSpelledOutOrdinalNumber:42];

The number would be 'forty-second'. I hope that helps you.

Community
  • 1
  • 1
evotopid
  • 5,288
  • 2
  • 26
  • 41
  • Learn something new everyday. – Stephen Canon Jul 16 '11 at 11:57
  • 1
    If you need to spell out in other languages, then it becomes more complicated. Internally `NSNumberFormatter` (`CFNumberFormatter`) uses ICU4C library, and ICU already can spell out ordinal number. However, it's not exposed through `NSNumberFormatter` API. You can have a look at my pod that does it - https://github.com/dimat/DMNumberSpellOutFormatter – Dmitry Jan 30 '17 at 12:37
5

This should have been accepted as the correct answer. NSNumberFormatter will do the job, and it's a standard approach, not some shaky workaround.

Here is an example:

NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterSpellOutStyle];
NSString* stringFromNumber = [numberFormatter stringFromNumber:your_number_goes_here];
NSLog( @"%@", stringFromNumber );

It will output 'one' for 1 'two' for 2 etc. Besides, it works perfectly for nonEnglish locales as well. For example, if you change the number formatter locale to German:

numberFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"DE"];

the code above will print: 'eins' for 1 'zwei' for 2 and so on.

Karoly Nyisztor
  • 3,505
  • 1
  • 26
  • 21
  • This answer is actually already included in mine if you look at my `getSpelledOutNumber:` method. The thing is. The question was how to produce ordinary numbers which this code alone doesn't, that's why I made that "shaky workaround". – evotopid Jan 05 '14 at 19:22
  • NSNumberFormatterOrdinalStyle is also terrific. – Matt Bearson Mar 29 '18 at 23:06
2

I once wrote a tool called vpi2english. It is part of my vpi toolbox, written in matlab. But the code is pretty simple really, and could be converted to another language if you choose. It essentially takes a (decimal) digit string, breaks it down into pieces of three digits at a time, and writes them each in words.

>> vpi2english(vpi('2331546567543686356564321'))
ans =
   two septillion, three hundred thirty one sextillion,
five hundred forty six quintillion, five hundred sixty seven quadrillion,
five hundred forty three trillion, six hundred eighty six billion,
three hundred fifty six million, five hundred sixty four thousand,
three hundred twenty one 

It currently works on numbers as large as 1 less than 1e306, which is as large as I could find names for such numbers online.

>> vpi2english(999999*vpi(10)^300)
ans =
nine hundred ninety nine centillion, nine hundred ninety nine novemnonagintillion