2010-02-24 14 views
10

J'ai une distance comme un flotteur et je cherche un moyen de le formater bien pour les lecteurs humains. Idéalement, j'aimerais que l'on passe de m à km au fur et à mesure que ça grossit et que l'on arrondisse bien le nombre. La conversion en miles serait un bonus. Je suis sûr que beaucoup de gens en ont eu besoin et j'espère qu'il y aura du code quelque part.Objective c formateur de chaîne pour les distances

Voilà comment je voudrais les formats:

  • 0-100m: 47m (en nombre entier)
  • 100-1000m: 325m ou 320m (arrondi à 5 ou 10 mètres les plus proches)
  • 1000-10000m: 1,2 km (arrondi au plus proche avec une décimale)
  • 10000m +: 21 km

S'il n'y a pas de code disponible, comment puis-je écrire mon propre formatter ?

Merci

Répondre

24

Aucune de ces solutions vraiment rencontré ce que je Je cherchais, donc je construit sur eux

#define METERS_TO_FEET 3.2808399 
#define METERS_TO_MILES 0.000621371192 
#define METERS_CUTOFF 1000 
#define FEET_CUTOFF  3281 
#define FEET_IN_MILES 5280 

- (NSString *)stringWithDistance:(double)distance { 
    BOOL isMetric = [[[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem] boolValue]; 

    NSString *format; 

    if (isMetric) { 
     if (distance < METERS_CUTOFF) { 
      format = @"%@ metres"; 
     } else { 
      format = @"%@ km"; 
      distance = distance/1000; 
     } 
    } else { // assume Imperial/U.S. 
     distance = distance * METERS_TO_FEET; 
     if (distance < FEET_CUTOFF) { 
      format = @"%@ feet"; 
     } else { 
      format = @"%@ miles"; 
      distance = distance/FEET_IN_MILES; 
     } 
    } 

    return [NSString stringWithFormat:format, [self stringWithDouble:distance]]; 
} 

// Return a string of the number to one decimal place and with commas & periods based on the locale. 
- (NSString *)stringWithDouble:(double)value { 
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; 
    [numberFormatter setLocale:[NSLocale currentLocale]]; 
    [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; 
    [numberFormatter setMaximumFractionDigits:1]; 
    return [numberFormatter stringFromNumber:[NSNumber numberWithDouble:value]]; 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    double distance = 5434.45; 
    NSLog(@"%f meters is %@", distance, [self stringWithDistance:distance]); 

    distance = 543.45; 
    NSLog(@"%f meters is %@", distance, [self stringWithDistance:distance]);  

    distance = 234234.45; 
    NSLog(@"%f meters is %@", distance, [self stringWithDistance:distance]);  
} 
+3

J'ai aimé cette solution. Création d'une catégorie 'NSString + Distance' basée dessus. Gist: https://gist.github.com/1397837 – Alex

+0

Merci, c'est exactement ce dont j'ai besoin pour CLLocationDistance. –

+0

Quelle licence/termes sont associés à cette catégorie. Je prévois de l'utiliser dans mon application. Dans mes licences VC, aimeriez-vous l'arbitrage? – Andrew

17

Oui vous devez écrire votre propre formatter, comme

#include <math.h> 
NSString* convertDistanceToString(float distance) { 
    if (distance < 100) 
     return [NSString stringWithFormat:@"%g m", roundf(distance)]; 
    else if (distance < 1000) 
     return [NSString stringWithFormat:@"%g m", roundf(distance/5)*5]; 
    else if (distance < 10000) 
     return [NSString stringWithFormat:@"%g km", roundf(distance/100)/10]; 
    else 
     return [NSString stringWithFormat:@"%g km", roundf(distance/1000)]; 
} 
... 
NSLog(@"The distance is %@", convertDistanceToString(1024)); 
+0

Merci beaucoup pour la réponse, c'était parfait pour ce dont j'avais besoin (et m'a fait gagner beaucoup de temps). –

2

Voici comment je le fais. Cela utilise les paramètres régionaux de l'utilisateur pour formater correctement la chaîne, ce que vous devriez probablement faire aussi.

// Returns a string representing the distance in the correct units. 
// If distance is greater than convert max in feet or meters, 
// the distance in miles or km is returned instead 
NSString* getDistString(float distance, int convertMax, BOOL includeUnit) { 
    NSString * unitName; 
    if (METRIC) { 
    unitName = @"m"; 
    if (convertMax != -1 && distance > convertMax) { 
     unitName = @"km"; 
     distance = distance/1000; 
    } 
    } else { 
    unitName = @"ft"; 
    if (convertMax != -1 && distance > convertMax) { 
     unitName = @"mi"; 
     distance = distance/5280; 
    } 
    distance = metersToFeet(distance); 
    } 

    if (includeUnit) return [NSString stringWithFormat:@"%@ %@", formatDecimal_1(distance), unitName]; 

    return formatDecimal_1(distance); 

} 
// returns a string if the number with one decimal place of precision 
// sets the style (commas or periods) based on the locale 
NSString * formatDecimal_1(float num) { 
    static NSNumberFormatter *numFormatter; 
    if (!numFormatter) { 
    numFormatter = [[[NSNumberFormatter alloc] init] retain]; 
    [numFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; 
    [numFormatter setLocale:[NSLocale currentLocale]]; 
    [numFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; 
    [numFormatter setMaximumFractionDigits:1]; 
    [numFormatter setMinimumFractionDigits:1]; 
    } 

    return [numFormatter stringFromNumber:F(num)]; 

} 
+0

Merci beaucoup. Je n'avais pas pensé à utiliser la localisation pour les formats numériques.Je vais devoir prendre le temps d'ajouter ceci au code que j'ai utilisé. –

+0

Comment savez-vous si l'utilisateur veut METRIC ou non? – ma11hew28

+0

Si elles ne vivent pas aux États-Unis, nous utilisons par défaut la mesure. Et ils peuvent l'échanger. Vous pouvez vérifier NSLocale pour obtenir leur emplacement. –

0

trouvé aujourd'hui poser la même question .... aller avec:

 
NSString *rvalue; 
    if (value > 1000) { 
     rvalue = [NSString stringWithFormat:@"%.02f km",value]; 
    }else { 
     rvalue = [NSString stringWithFormat:@"%.02f m",value]; 
    } 

pourrait envelopper cela dans une méthode, le cas échéant

23

iOS 7 et OS X 10.9 introduit pour MKDistanceFormatter Distances: formatage

Exemple de code:

double myDistance = 21837.0f; 

MKDistanceFormatter *df = [[MKDistanceFormatter alloc]init]; 
df.unitStyle = MKDistanceFormatterUnitStyleAbbreviated; 

NSLog(@"myDistance is %@", [df stringFromDistance: myDistance]); 

Mise à jour:

Il semble que MKDistanceFormatter arrondit la valeur d'entrée en quelque sorte. Par exemple. quand je mets myDistance à 111.0 je reçois "100 m".

4

NSLengthFormatter qui a été introduit avec iOS 8 et OS X 10.10 est une option que les gens devraient connaître.

NSLengthFormatter *lengthFormatter = [[NSLengthFormatter alloc] init]; 
    lengthFormatter.unitStyle = NSFormattingUnitStyleShort; 

    NSLog(@"distance = %@", [lengthFormatter stringFromMeters:meters]); 

Cependant, NSLengthFormatter a ne pas utiliser les unités impériales dans les endroits où ils utilisent métrique, sauf pour les distances.

+0

Ce serait bien s'il renvoyait _feet_ au lieu de _yards_. – inorganik

-1

Pour ceux qui recherchent une version 2.0 rapide. Porté de @MattDiPasquale

extension Double { 
    func toDistanceString() -> String { 
    let METERS_TO_FEET = 3.2808399 
    let METERS_CUTOFF = 1000.0 
    let FEET_CUTOFF = 3281.0 
    let FEET_IN_MILES = 5280.0 

    let format:String 
    if (NSLocale.isMetric()) { 
     if (self < METERS_CUTOFF) { 
     format = "\(self.stringWithDecimals(0)) metres" 
     } else { 
     format = "\((self/1000).stringWithDecimals(1)) km"; 
     } 
    } else { // assume Imperial/U.S. 
     let feet = self * METERS_TO_FEET; 
     if (feet < FEET_CUTOFF) { 
     format = "\(feet.stringWithDecimals(0)) feet"; 
     } else { 
     format = "\((self/FEET_IN_MILES).stringWithDecimals(1)) miles"; 
     } 
    } 
    return format 
    } 

    func stringWithDecimals(decimals:Int) -> String { 
    return String(format: "%.\(decimals)f", self) 
    } 
} 

extension NSLocale { 
    class func isMetric() -> Bool { 
    let locale = NSLocale.currentLocale() 
    return locale.objectForKey(NSLocaleUsesMetricSystem) as! Bool 
    } 
}