NSNumberFormatter et 'e' 'e' 'nd' 'rd' (ordinale) nombre de terminaisons
y a-t-il un moyen d'utiliser NSNumberFormatter pour obtenir les terminaisons 'th' 'st' 'nd' rd 'number?
EDIT:
semble ne pas exister. Voici ce que j'utilise.
+(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];
}
adapté de la réponse de nickf ici y a-t-il un moyen facile dans .NET pour obtenir "st", "nd", "rd" et "th" fin pour les nombres?
19 réponses
puisque la question demandait un formateurde nombre, voici un grossier que j'ai fait.
//
// OrdinalNumberFormatter.h
//
#import <Foundation/Foundation.h>
@interface OrdinalNumberFormatter : NSNumberFormatter {
}
@end
et la mise en œuvre:
//
// 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
instanciez ceci comme un objet Interface Builder et attachez la sortie formatter du champ de texte à cet objet. Pour un contrôle plus fin (par exemple pour définir les valeurs maximum et minimum, vous devez créer une instance du formatteur, définir les propriétés comme vous le souhaitez et l'attacher au champ de texte en utilisant son setFormatter:
méthode.
vous pouvez télécharger la classe de GitHub (y compris un exemple de projet)
la bonne façon de procéder à partir de iOS 9 est:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterOrdinalStyle;
NSLog(@"%@", [numberFormatter stringFromNumber:@(1)]); // 1st
NSLog(@"%@", [numberFormatter stringFromNumber:@(2)]); // 2nd
NSLog(@"%@", [numberFormatter stringFromNumber:@(3)]); // 3rd, etc.
alternativement:
NSLog(@"%@", [NSString localizedStringFromNumber:@(1)
numberStyle:NSNumberFormatterOrdinalStyle]); // 1st
Cela fait l'affaire dans une méthode (pour l'anglais). Merci nickf https://stackoverflow.com/a/69284/1208690 pour le code original en PHP, je viens de l'adapter à 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;
}
D'autres solutions Swift ne produisent pas de résultat correct et contiennent des erreurs. J'ai traduit CmKndy solution en 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)"
}
}
résultat de l'essai: 0e 1er 2ème 3e 4e 5ème Six Sept 8ème 9ème 10ème 11ème Douze Treize 14ème 15ème 16e Dix sept 18ème 19ème 20ème 21ème Vingt deux 23ème
Comme d'iOS 9
Swift 3
let value = 1
let formatter = NumberFormatter()
formatter.numberStyle = .ordinal
formatter.string(from: NSNumber(short: value))
ajout D'une autre implémentation comme méthode de classe. Je n'ai vu cette question postée qu'après l'avoir implémentée à partir d'un exemple 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;
}
c'est assez simple en anglais. Voici une extension swift:
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
}
}
}
alors appelez quelque chose comme:
cell.label_position.text = (path.row + 1).ordinal
Voici une extension Swift compacte adaptée à tous les types d'entiers:
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"
}
}
}
exemple d'usage:
let numbers = (0...30).map { "151910920".ordinalString() }
print(numbers.joinWithSeparator(", "))
sortie:
0e, 1er, 2e, 3e, 4e, 5e, 6e, 7e, 8e, 9e, 10e, 11e, 12e, 13e, 14e, 15e, 16e, 17e, 18e, 19e, 20e, 21e, 22e, 23e, 24e, 25e, 26e, 27e, 28e, 29e, 30e
Je ne suis pas au courant de cette capacité. Toutefois, il est possible de le faire vous-même. En anglais, l'ordinal (th, st, nd, rd, etc) a un motif très simple:
si le nombre se termine par: = > Use:
- 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
cela n'épelle pas le mot pour vous, mais cela vous permettra de faire quelque chose comme:" 42nd"," 1,340,697 th", etc.
cela devient plus compliqué si vous en avez besoin localisé.
Un nettoyage Swift version (en anglais seulement):
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"
}
}
peut être utilisé comme extension pour 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"
}
}
}
-- Swift 4 --
let num = 1
let formatter = NumberFormatter()
formatter.numberStyle = .ordinal
let day = formatter.string(from: NSNumber(value: num))
print(day!)
result - 1st
l'exemple suivant montre comment traiter un nombre. Il est en c # mais il peut facilement être converti à n'importe quelle langue.
cela convertira la date en chaîne et ajoutera aussi ordinal dans la date. Vous pouvez modifier la date formatte en changeant NSDateFormatter object
-(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;
}
il y a une solution simple pour ce
let formatter = NumberFormatter()
formatter.numberStyle = .ordinal
let first = formatter.string(from: 1) // 1st
let second = formatter.string(from: 2) // 2nd
Referance: hackingwithswift.com
Voici une solution rapide qui tourne à travers les langues préférées de l'utilisateur jusqu'à ce qu'il en trouve une avec des règles connues (qui sont assez faciles à ajouter) pour les nombres ordinaux:
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)
}
}
beaucoup de solutions ici ne gèrent pas des nombres plus élevés comme 112. Voici une façon simple de le faire.
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);
}
Voici une courte extension Int pour la langue anglaise qui rend compte aussi et affiche des nombres entiers négatifs correctement:
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 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;
}
C'était mon implémentation brute de force à prendre une représentation NSString* de la date et retourner la valeur ordinale. Je sens que c'est beaucoup plus facile à lire.
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" };