Objective c string formatter for distances

后端 未结 7 1809
借酒劲吻你
借酒劲吻你 2021-02-02 01:45

I have a distance as a float and I\'m looking for a way to format it nicely for human readers. Ideally, I\'d like it to change from m to km as it gets bigger, and to round the n

相关标签:
7条回答
  • 2021-02-02 02:21

    None of these solutions really met what I was looking for, so I built on them:

    #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]);    
    }
    
    0 讨论(0)
  • 2021-02-02 02:26

    iOS 7 and OS X 10.9 introduced MKDistanceFormatter for formatting distances:

    Code Example:

    double myDistance = 21837.0f;
    
    MKDistanceFormatter *df = [[MKDistanceFormatter alloc]init];
    df.unitStyle = MKDistanceFormatterUnitStyleAbbreviated;
    
    NSLog(@"myDistance is %@", [df stringFromDistance: myDistance]);
    

    Update:

    It seems that MKDistanceFormatter is rounding the input value somehow. E.g. when I set myDistance to 111.0 I get "100 m".

    0 讨论(0)
  • 2021-02-02 02:28

    NSLengthFormatter which was introduced with iOS 8 and OS X 10.10 is an option people should be aware of.

        NSLengthFormatter *lengthFormatter = [[NSLengthFormatter alloc] init];
        lengthFormatter.unitStyle = NSFormattingUnitStyleShort;
    
        NSLog(@"distance = %@", [lengthFormatter stringFromMeters:meters]);
    

    However, NSLengthFormatter has doesn't use Imperial units in those locales where they use metric except for distances.

    0 讨论(0)
  • 2021-02-02 02:31

    Yes you need to write your own formatter, like

    #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 讨论(0)
  • 2021-02-02 02:32

    found this today asking the same question....going with :

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

    could wrap this in a method, if need be

    0 讨论(0)
  • 2021-02-02 02:40

    For those looking for a swift 2.0 version. Ported from @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
      }
    }
    
    0 讨论(0)
提交回复
热议问题