NSNumberFormatter y 'th' 'st' 'nd' 'rd' (ordinal) número de terminaciones

¿Hay alguna forma de utilizar NSNumberFormatter para get las terminaciones de número 'th' 'st' 'nd' 'rd'?

EDITAR:

Parece que no existe. Esto es lo que estoy usando.

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

Adaptado de la respuesta de nickf aquí ¿Hay una manera fácil en .NET para get "st", "nd", "rd" y "th" finales para los numbers?

Dado que la pregunta solicitó un formateador de numbers, he aquí una aproximada que hice.

 // // OrdinalNumberFormatter.h // #import <Foundation/Foundation.h> @interface OrdinalNumberFormatter : NSNumberFormatter { } @end 

y la implementación:

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

Haz una instancia de este como un object de Generador de interfaces y adjunta la salida del formateador del Campo de text. Para un control más fino (como establecer valores máximos y mínimos, debe crear una instancia del formateador, establecer las properties como desee y adjuntarlo al campo de text utilizando su método setFormatter:

Puede download la class de GitHub (incluido un proyecto de ejemplo)

La forma correcta de hacerlo desde iOS 9 en adelante es:

 NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; numberFormatter.numberStyle = NSNumberFormatterOrdinalStyle; NSLog(@"%@", [numberFormatter stringFromNumber:@(1)]); // 1st NSLog(@"%@", [numberFormatter stringFromNumber:@(2)]); // 2nd NSLog(@"%@", [numberFormatter stringFromNumber:@(3)]); // 3rd, etc. 

Esto hace el truco en un método (para inglés). Gracias nickf https://stackoverflow.com/a/69284/1208690 para el código original en PHP, acabo de adaptarlo al 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; } 

Otras soluciones Swift no producen el resultado correcto y contienen errores. He traducido la solución CmKndy a 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)" } } 

Resultado de la testing: 0º 1º 2º 3º 4º 5º 6º 7º 8º 9º 10º 11º 12º 13º 14º 15º 16º 17º 18º 19º XX 20º 22º 23º

Simplemente agregando otra implementación como método de class. No vi esta pregunta publicada hasta después de implementar esto a partir de un ejemplo en 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; } 

Es bastante simple en inglés. Aquí hay una extensión rápida:

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

Luego llama algo así:

  cell.label_position.text = (path.row + 1).ordinal 

Aquí hay una extensión Swift compacta adecuada para todos los types de integers:

 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" } } } 

Ejemplo de uso:

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

Salida:

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

A partir de iOS 9

Swift 3

 let value = 1 let formatter = NSNumberFormatter() formatter.numberStyle = .ordinalStyle formatter.string(from: NSNumber(short: value)) 

No conozco esta capacidad. Sin embargo, es posible hacerlo usted mismo. En inglés, el ordinal (th, st, nd, rd, etc.) tiene un patrón muy simple:

Si el número termina con: => Usar:

  • 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

Esto no explicará la palabra para ti, pero te permitirá hacer algo así como: "42nd", "1,340,697th", etc.

Esto se vuelve más complicado si lo necesita localizado.

Esto convertirá la date en cadena y también agregará ordinal en la date. Puede modificar el formatte de la date al cambiar el object NSDateFormatter

 -(NSString*) getOrdinalDateString:(NSDate*)date { NSString* string=@""; 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; } 

Una versión Swift limpia (solo en inglés):

 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" } } 

Se puede hacer como una extensión para 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" } } } 

El siguiente ejemplo muestra cómo manejar cualquier número. Está en c # sin embargo, se puede convertir fácilmente a cualquier idioma.

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

Aquí hay una solución Swift que recorre los idiomas preferidos del usuario hasta encontrar una con reglas conocidas (que son bastante fáciles de agregar) para numbers ordinales:

 extension Int { var localizedOrdinal: String { func ordinalSuffix(int: Int) -> String { for language in NSLocale.prefernetworkingLanguages() 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) } } 

Muchas de las soluciones aquí no manejan numbers más altos como 112. Aquí hay una manera simple de hacerlo.

 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); } 

Aquí hay una extensión Int corta para el idioma inglés que también representa y muestra numbers integers negativos correctamente:

 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 } } 
 - (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 eg 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; } 

Hay una solución simple para esto

 let formatter = NumberFormatter() formatter.numberStyle = .ordinal let first = formatter.string(from: 1) let second = formatter.string(from: 2) let tenth = formatter.string(from: 10) let oneThousandAndFirst = formatter.string(from: 1001) 

Referance : hackingwithswift.com

Esta fue mi implementación de fuerza bruta para tomar una representación NSString * de la date y devolver el valor ordinal. Siento que es mucho más fácil de leer.

 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" };