NSNumberFormatter и 'th' 'st' 'nd' 'rd' (порядковый номер)
Есть ли способ использовать 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];
}
Адаптировано из ответа на nickf здесь
Есть ли простой способ в .NET получить "st" , "nd" , "rd" и "th" окончания для номеров?
Ответы
Ответ 1
Поскольку вопрос задан для числа форматировщиков, здесь был грубый, который я сделал.
//
// 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 и прикрепите к нему текстовое поле Textatter. Для более точного управления (например, для установки максимальных и минимальных значений вы должны создать экземпляр форматирования, установить свойства по своему усмотрению и прикрепить его к текстовому полю с помощью метода setFormatter:
.
Вы можете загрузить класс из GitHub (включая примерный проект)
Ответ 2
Правильный способ сделать это с 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
Ответ 3
Это делает трюк одним способом (для английского). Спасибо nickf fooobar.com/questions/35945/... для исходного кода в 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;
}
Ответ 4
Другие решения 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)"
}
}
результат теста:
0th
первый
второй
третий
четвёртая
пятые
шестые
седьмые
восьмых
девятую
десятые
11
12
13-й
четырнадцатый
пятнадцатый
шестнадцатый
семнадцатый
восемнадцатый
девятнадцатый
двадцатый
двадцать первый
двадцать второй
Двадцать третий
Ответ 5
Начиная с 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
Просто добавление другой реализации в качестве метода класса. Я не видел этот вопрос, пока я не выполнил это из примера в 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;
}
Ответ 7
Это довольно просто на английском языке. Здесь быстрое расширение:
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
Ответ 8
Здесь имеется компактное расширение 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(", "))
Вывод:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30th
Ответ 9
- Swift 4 -
let num = 1
let formatter = NumberFormatter()
formatter.numberStyle = .ordinal
let day = formatter.string(from: NSNumber(value: num))
print(day!)
result - 1st
Ответ 10
Я не знаю об этой возможности. Однако это можно сделать сами. На английском языке порядковый номер (th, st, nd, rd и т.д.) Имеет действительно простой шаблон:
Если число заканчивается на: = > Использовать:
- 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
Это не будет говорить вам слово, но это позволит вам сделать что-то вроде: "42nd", "1,340,697th" и т.д.
Это становится более сложным, если вам нужно его локализовать.
Ответ 11
Чистая версия 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"
}
}
}
Ответ 12
В следующем примере показано, как обрабатывать любое число. Он в С# однако может легко преобразовываться на любой язык.
http://www.bytechaser.com/en/functions/b6yhfyxh78/convert-number-to-ordinal-like-1st-2nd-in-c-sharp.aspx
Ответ 13
Для этого есть простое решение
let formatter = NumberFormatter()
formatter.numberStyle = .ordinal
let first = formatter.string(from: 1) // 1st
let second = formatter.string(from: 2) // 2nd
Ссылка: hackingwithswift.com
Ответ 14
Это преобразует дату в строку, а также добавит ординал в дату. Вы можете изменить формат даты, изменив объект NSDateFormatter
-(NSString*) getOrdinalDateString:(NSDate*)date
{
NSString* [email protected]"";
NSDateComponents *components = [[NSCalendar currentCalendar] components: NSCalendarUnitDay fromDate:date];
if(components.day == 1 || components.day == 21 || components.day == 31)
string = @"st";
else if (components.day == 2 || components.day == 22)
string = @"nd";
else if (components.day == 3 || components.day == 23)
string = @"rd";
else
string = @"th";
NSDateFormatter *dateFormatte = [[NSDateFormatter alloc] init];
[dateFormatte setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatte setDateFormat:[NSString stringWithFormat:@"d'%@' MMMM yyyy",string]];
NSString *dateString = [dateFormatte stringFromDate:date];
return dateString;
}
Ответ 15
Здесь быстрое решение, которое циклически проходит через предпочтительные языки пользователя, пока не найдет один с известными правилами (которые довольно легко добавить) для порядковых номеров:
extension Int {
var localizedOrdinal: String {
func ordinalSuffix(int: Int) -> String {
for language in NSLocale.preferredLanguages() as [String] {
switch language {
case let l where l.hasPrefix("it"):
return "°"
case let l where l.hasPrefix("en"):
switch int {
case let x where x != 11 && x % 10 == 1:
return "st"
case let x where x != 12 && x % 10 == 2:
return "nd"
case let x where x != 13 && x % 10 == 3:
return "rd"
default:
return "st"
}
default:
break
}
}
return ""
}
return "\(self)" + ordinalSuffix(self)
}
}
Ответ 16
Многие из решений здесь не обрабатывают более высокие числа, такие как 112. Вот простой способ сделать это.
for(int i=0;i<1000;i++){
int n = i;
NSString* ordinal = @"th";
if(n%10==1 && n%100!=11) ordinal = @"st";
if(n%10==2 && n%100!=12) ordinal = @"nd";
if(n%10==3 && n%100!=13) ordinal = @"rd";
NSLog(@"You are the %d%@",i,ordinal);
}
Ответ 17
Здесь короткое расширение Int для английского языка, которое также учитывает и отображает отрицательные целые числа:
extension Int {
func ordinal() -> String {
let suffix: String!
// treat negative numbers as positive for suffix
let number = (self < 0 ? self * -1 : self)
switch number % 10 {
case 0:
suffix = self != 0 ? "th" : ""
case 1:
suffix = "st"
case 2:
suffix = "nd"
case 3:
suffix = "rd"
default:
suffix = "th"
}
return String(self) + suffix
}
}
Ответ 18
- (NSString *) formatOrdinalNumber:(NSInteger )number{
NSString *result = nil;
//0 remains just 0
if (number == 0) {
result = @"0";
}
//test for number between 3 and 21 as they follow a
//slightly different rule and all end with th
else if (number > 3 && number < 21)
{
result = [NSString stringWithFormat:@"%ld th",(long)number];
}
else {
//return the last digit of the number e.g. 102 is 2
NSInteger lastdigit = number % 10;
switch (lastdigit)
{
case 1: result = [NSString stringWithFormat:@"%ld st",(long)number]; break;
case 2: result = [NSString stringWithFormat:@"%ld nd",(long)number]; break;
case 3: result = [NSString stringWithFormat:@"%ld rd",(long)number]; break;
default: result = [NSString stringWithFormat:@"%ld th",(long)number];
}
}
return result;
}
Ответ 19
Вы можете попробовать это, это очень упрощенно.
function numberToOrdinal(n) {
if (n==0) {
return n;
}
var j = n % 10,
k = n % 100;
if (j == 1 && k != 11) {
return n + "st";
}
if (j == 2 && k != 12) {
return n + "nd";
}
if (j == 3 && k != 13) {
return n + "rd";
}
return n + "th";
}
Ответ 20
Это была моя переборка для выполнения представления NSString * даты и возврата порядкового значения. Я чувствую, что это намного легче читать.
NSDictionary *ordinalDates = @{
@"1": @"1st",
@"2": @"2nd",
@"3": @"3rd",
@"4": @"4th",
@"5": @"5th",
@"6": @"6th",
@"7": @"7th",
@"8": @"8th",
@"9": @"9th",
@"10": @"10th",
@"11": @"11th",
@"12": @"12th",
@"13": @"13th",
@"14": @"14th",
@"15": @"15th",
@"16": @"16th",
@"17": @"17th",
@"18": @"18th",
@"19": @"19th",
@"20": @"20th",
@"21": @"21st",
@"22": @"22nd",
@"23": @"23rd",
@"24": @"24th",
@"25": @"25th",
@"26": @"26th",
@"27": @"27th",
@"28": @"28th",
@"29": @"29th",
@"30": @"30th",
@"31": @"31st" };