NSNumberFormatter и 'th' 'st' 'nd' 'rd' (порядковые) числа - PullRequest
30 голосов
/ 23 июля 2010

Есть ли способ использовать NSNumberFormatter для получения окончаний числа 'th' 'st' 'nd' 'rd'?

EDIT:

Похоже, его не существует.Вот что я использую.

+(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];
}

Адаптировано из ответа Никфа здесь Есть ли простой способ в .NET получить окончания "st", "nd", "rd" и "th"для номеров?

Ответы [ 20 ]

34 голосов
/ 09 мая 2016

Правильный способ сделать это начиная с iOS 9 и далее:

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterOrdinalStyle;

NSLog(@"%@", [numberFormatter stringFromNumber:@(1)]); // 1st
NSLog(@"%@", [numberFormatter stringFromNumber:@(2)]); // 2nd
NSLog(@"%@", [numberFormatter stringFromNumber:@(3)]); // 3rd, etc.

В качестве альтернативы:

NSLog(@"%@", [NSString localizedStringFromNumber:@(1)
                                     numberStyle:NSNumberFormatterOrdinalStyle]); // 1st
22 голосов
/ 20 апреля 2012

Это делает трюк в одном методе (для английского). Спасибо nickf https://stackoverflow.com/a/69284/1208690 за оригинальный код на PHP, я просто адаптировал его к objective C: -

-(NSString *) addSuffixToNumber:(int) number
{
    NSString *suffix;
    int ones = number % 10;
    int tens = (number/10) % 10;

    if (tens ==1) {
        suffix = @"th";
    } else if (ones ==1){
        suffix = @"st";
    } else if (ones ==2){
        suffix = @"nd";
    } else if (ones ==3){
        suffix = @"rd";
    } else {
        suffix = @"th";
    }

    NSString * completeAsString = [NSString stringWithFormat:@"%d%@", number, suffix];
    return completeAsString;
}
15 голосов
/ 19 января 2015

Другие решения Swift не дают правильного результата и содержат ошибки.Я перевел решение CmKndy в Swift

extension Int {

    var ordinal: String {
        var suffix: String
        let ones: Int = self % 10
        let tens: Int = (self/10) % 10
        if tens == 1 {
            suffix = "th"
        } else if ones == 1 {
            suffix = "st"
        } else if ones == 2 {
            suffix = "nd"
        } else if ones == 3 {
            suffix = "rd"
        } else {
            suffix = "th"
        }
        return "\(self)\(suffix)"
    }

}

Результат теста: 0-й 1-й 3-й 4-й 5-й 6-й 7-й 8-й 9-й 10-й 11-й 12-й 13-й 14-й 15-й 16-й 17-й 18-й 19-й 20-й 21-й 22-й 23-й

14 голосов
/ 23 июля 2010

Поскольку вопрос задан для числового форматера, вот грубый вопрос, который я сделал.

//
//  OrdinalNumberFormatter.h
//

#import <Foundation/Foundation.h>


@interface OrdinalNumberFormatter : NSNumberFormatter {

}

@end

и реализация:

//
//  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

Создайте экземпляр как объект Interface Builder и присоедините к нему выход форматера текстового поля. Для более точного управления (например, установки максимальных и минимальных значений, вы должны создать экземпляр средства форматирования, установить свойства по своему желанию и прикрепить его к текстовому полю, используя метод setFormatter:.

Вы можете скачать класс с GitHub (включая пример проекта)

13 голосов
/ 23 февраля 2017

Начиная с iOS 9

Swift 4

private var ordinalFormatter: NumberFormatter = {
    let formatter = NumberFormatter()
    formatter.numberStyle = .ordinal
    return formatter
}()

extension Int {
    var ordinal: String? {
        return ordinalFormatter.string(from: NSNumber(value: self))
    }
}

Вероятно, лучше иметь форматер вне расширения ...

6 голосов
/ 14 ноября 2014

Это довольно просто на английском языке. Вот быстрое расширение:

extension Int {
    var ordinal: String {
        get {
            var suffix = "th"
            switch self % 10 {
                case 1:
                    suffix = "st"
                case 2:
                    suffix = "nd"
                case 3:
                    suffix = "rd"
                default: ()
            }
            if 10 < (self % 100) && (self % 100) < 20 {
                suffix = "th"
            }
            return String(self) + suffix
        }
    }
}

Тогда назовите что-то вроде:

    cell.label_position.text = (path.row + 1).ordinal
5 голосов
/ 07 июня 2012

Просто добавив еще одну реализацию в качестве метода класса.Я не видел этот вопрос опубликованным до тех пор, пока я не реализовал это из примера в php.

+ (NSString *)buildRankString:(NSNumber *)rank
{
    NSString *suffix = nil;
    int rankInt = [rank intValue];
    int ones = rankInt % 10;
    int tens = floor(rankInt / 10);
    tens = tens % 10;
    if (tens == 1) {
        suffix = @"th";
    } else {
        switch (ones) {
            case 1 : suffix = @"st"; break;
            case 2 : suffix = @"nd"; break;
            case 3 : suffix = @"rd"; break;
            default : suffix = @"th";
        }
    }
    NSString *rankString = [NSString stringWithFormat:@"%@%@", rank, suffix];
    return rankString;
}
5 голосов
/ 15 марта 2016

Вот компактное расширение Swift, подходящее для всех целочисленных типов:

extension IntegerType {
    func ordinalString() -> String {
        switch self % 10 {
        case 1...3 where 11...13 ~= self % 100: return "\(self)" + "th"
        case 1:    return "\(self)" + "st"
        case 2:    return "\(self)" + "nd"
        case 3:    return "\(self)" + "rd"
        default:   return "\(self)" + "th"
        }
    }
}

Пример использования:

let numbers = (0...30).map { $0.ordinalString() }
print(numbers.joinWithSeparator(", "))

Вывод:

0th, 1st,2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26,27, 28, 29, 30

4 голосов
/ 29 декабря 2017

- Swift 4 -

     let num = 1
     let formatter = NumberFormatter()
     formatter.numberStyle = .ordinal
     let day = formatter.string(from: NSNumber(value: num))

     print(day!)
     result - 1st
3 голосов
/ 21 февраля 2016

Чистая версия Swift (только для английского):

func ordinal(number: Int) -> String {
    if (11...13).contains(number % 100) {
        return "\(number)th"
    }
    switch number % 10 {
        case 1: return "\(number)st"
        case 2: return "\(number)nd"
        case 3: return "\(number)rd"
        default: return "\(number)th"
    }
}

Можно сделать как расширение для Int:

extension Int {

    func ordinal() -> String {
        return "\(self)\(ordinalSuffix())"
    }

    func ordinalSuffix() -> String {
        if (11...13).contains(self % 100) {
            return "th"
        }
        switch self % 10 {
            case 1: return "st"
            case 2: return "nd"
            case 3: return "rd"
            default: return "th"
        }
    }

}
...