ios objective-c nsnumberformatter

ios - NSNumberFormatter y ''th'' ''st'' ''nd'' ''rd''(ordinal) terminaciones de números



objective-c (19)

¿Hay alguna forma de usar NSNumberFormatter para obtener los finales de los números ''th'' ''n'' ''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í. ¿Existe una manera fácil en .NET de obtener los finales "st", "nd", "rd" y "th" para los números?


- Swift 4 -

let num = 1 let formatter = NumberFormatter() formatter.numberStyle = .ordinal let day = formatter.string(from: NSNumber(value: num)) print(day!) result - 1st


A partir de iOS 9

Swift 3

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


Aquí hay una extensión Swift compacta adecuada para todos los tipos de enteros:

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º, 4º, 5º, 6º, 7º, 8º, 9º, 10º, 11º, 12º, 13º, 14º, 15º, 16º, 17º, 18º, 19º, 20º, 21º, 22º, 23º, 24º, 24º, 25, 26, 27, 28, 29, 30, 30


Aquí hay una extensión corta de Int para el idioma inglés que también representa y muestra los enteros 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 } }


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

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


Dado que la pregunta para un formateador de números, aquí hay 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

Cree una instancia como un objeto de Interface Builder y adjunte la salida del formateador del campo de texto. Para un control más preciso (como establecer valores máximos y mínimos, debe crear una instancia del formateador, establecer las propiedades que desee y adjuntarla al campo de texto usando su método setFormatter: .

Puede descargar la clase de GitHub (incluido un proyecto de ejemplo)



Es bastante sencillo 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 } } }

Entonces llama algo como:

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


Esta fue mi implementación de fuerza bruta para tomar una representación NSString * de la fecha 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" };


Esto convertirá la fecha en una cadena y también agregará ordinales en la fecha. Puede modificar el formato de fecha cambiando el objeto 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; }


Esto hace el truco en un método (para inglés). Gracias a Nickf https://.com/a/69284/1208690 por el código original en PHP, lo adapté 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; }


Hay una solución simple para esto.

let formatter = NumberFormatter() formatter.numberStyle = .ordinal let first = formatter.string(from: 1) // 1st let second = formatter.string(from: 2) // 2nd

hackingwithswift.com : hackingwithswift.com


La forma correcta de hacer esto 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.

Alternativamente:

NSLog(@"%@", [NSString localizedStringFromNumber:@(1) numberStyle:NSNumberFormatterOrdinalStyle]); // 1st


Muchas de las soluciones aquí no manejan números más altos como 112. Esta es una forma 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); }


No estoy al tanto de 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: => Uso:

  • 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, pero le permitirá hacer algo como: "42nd", "1,340,697th", etc.

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


Otras soluciones Swift no producen resultados correctos y contienen errores. He traducido la solución de 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 prueba: 0º 1º 2º 3º 4º 5º 6º 7º 7º 8º 9º 10º 11º 13º 13º 14º 16º 17º 18º 18º 20º 21º 22º 23º


Solo añadiendo otra implementación como método de clase. No vi esta pregunta publicada hasta después de que implementé esto desde 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; }


Una versión Swift limpia (solo para 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" } } }


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