我的iOS应用程序在不同的本地化(en_US,en_AU,ja_JP等)中显示不同的货币(USD,JPY,AUD,EUR).
对于日本地区/语言(都设置在我的设备上),如果我有:
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init]; fmt.numberStyle = NSNumberFormatterCurrencyStyle; fmt.currencyCode = @"JPY"; NSString *labelText = [fmt stringFromNumber:@1000000];
我的标签文字是¥1,000,000.但是,日文和中文的数字大于10,000可能写为100万円,这是我想要的输出.
我想在我的代码检查区域设置区域中避免使用逻辑块,但是我觉得这就是我所面对的(例如,使用方法调用fmt.multipler = @(1/10000)来划分1,000获得正确的价值10,000).
解决方法
编辑:最新的这里:
https://gist.github.com/fjolnir/cd72ea39be1476023adf
旧线程,但是我在找到一个解决方案的时候遇到它,所以我想我会发布我的实现.
格式化程序本身不处理円的放置,但这在外面很容易做到. (如下例所示)
下面的预期产出是:
2015-03-11 18:00:13.376 LENumberFormatter[82736:3604947] 12億3,460万円 2015-03-11 18:00:13.377 LENumberFormatter[82736:3604947] 25円
–
@import Foundation; @import ObjectiveC.message; typedef NS_ENUM(NSUInteger,LENumberFormatterAbbreviationStyle) { kLEAbbreviateShort,// 2.5m kLEAbbreviateNormal // 2m 5k }; @interface LENumberFormatter : NSNumberFormatter @property(nonatomic) BOOL abbreviateLargeNumbers; @property(nonatomic) LENumberFormatterAbbreviationStyle abbreviationStyle; @end @implementation LENumberFormatter - (instancetype)init { if((self = [super init])) { self.abbreviationStyle = [self _usingKanjiNumbers] ? kLEAbbreviateNormal : kLEAbbreviateShort; } return self; } - (NSString *)stringForObjectValue:(id const)aObj { if(!_abbreviateLargeNumbers || ![aObj isKindOfClass:[NSNumber class]]) return [super stringForObjectValue:aObj]; // Copy ourselves to get format the partial digits using the settings on self LENumberFormatter * const partialFormatter = [self copy]; partialFormatter.currencySymbol = @""; if(_abbreviationStyle == kLEAbbreviateNormal) partialFormatter.maximumFractionDigits = 0; NSString *(^partialFormat)(NSNumber*) = ^(NSNumber *num) { NSString *(*superImp)(struct objc_super*,SEL,NSNumber*) = (void*)&objc_msgSendSuper; return superImp(&(struct objc_super) { partialFormatter,self.superclass },_cmd,num); }; double n = [aObj doubleValue]; BOOL const shortFormat = _abbreviationStyle == kLEAbbreviateShort; NSDictionary * const separators = [self _localizedGroupingSeparators]; NSArray * const separatorExponents = [separators.allKeys sortedArrayUsingSelector:@selector(compare:)]; BOOL const currencySymbolIsSuffix = [self.positiveFormat hasSuffix:@"¤"]; NSMutableString * const result = currencySymbolIsSuffix || self.numberStyle != NSNumberFormatterCurrencyStyle ? [NSMutableString new] : [self.currencySymbol mutableCopy]; NSUInteger significantDigits = 0; NSNumber *lastExp = nil; for(NSNumber *exp in separatorExponents.reverSEObjectEnumerator) { double divisor = pow(10,exp.shortValue); if(divisor > n) continue; if(lastExp) significantDigits += lastExp.doubleValue - exp.doubleValue; lastExp = exp; if(self.usesSignificantDigits && significantDigits >= self.maximumSignificantDigits) break; double partialNum = shortFormat ? n/divisor : floor(n/divisor); NSString * const digits = [self _groupRecursively] && ![exp isEqual:@0] ? [partialFormatter stringFromNumber:@(partialNum)] : partialFormat(@(partialNum)); [result appendFormat:@"%@%@",digits,separators[exp]]; n = fmod(n,divisor); if(shortFormat) break; // Just use a float+first hit // If we make it here,partialNum is integral and we can use log10 to find the number of digits significantDigits += log10(partialNum) + 1; partialFormatter.maximumSignificantDigits -= digits.length; } if(n > 0 && !shortFormat && (!self.usesSignificantDigits || significantDigits < self.maximumSignificantDigits)) { partialFormatter.maximumFractionDigits = self.maximumFractionDigits; [result appendString:partialFormat(@(n))]; } if(self.numberStyle == NSNumberFormatterCurrencyStyle && currencySymbolIsSuffix && self.currencySymbol) [result appendString:self.currencySymbol]; return result.length > 0 ? [result stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet] : [super stringForObjectValue:aObj]; } - (BOOL)_usingKanjiNumbers { return [self.locale.localeIdentifier rangeOfString:@"^(ja|zh)_" options:NSRegularExpressionSearch].location != NSNotFound; } - (NSDictionary *)_localizedGroupingSeparators { if(self._usingKanjiNumbers) return @{ @2: @"百",@3: @"千",@4: @"万",@8: @"億" }; else { NSBundle * const bundle = [NSBundle bundleForClass:self.class]; return @{ @3: [bundle localizedStringForKey:@"thousandSuffix" value:@"k " table:nil],@6: [bundle localizedStringForKey:@"millionSuffix" value:@"m " table:nil] }; } } - (BOOL)_groupRecursively { // Return _usingKanjiNumbers if you want: // 12億3千4百56万7千8百90 // Rather than: // 1億2,3456万7千8百90 return NO; } - (instancetype)copyWithZone:(NSZone * const)aZone { LENumberFormatter * const copy = [super copyWithZone:aZone]; copy.abbreviateLargeNumbers = _abbreviateLargeNumbers; copy.abbreviationStyle = _abbreviationStyle; return copy; } @end int main(int argc,char *argv[]) { @autoreleasepool { LENumberFormatter * const f = [LENumberFormatter new]; f.locale = [NSLocale localeWithLocaleIdentifier:@"ja_JP"]; // f.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"]; f.numberStyle = NSNumberFormatterCurrencyStyle; f.abbreviateLargeNumbers = YES; f.abbreviationStyle = kLEAbbreviateNormal; // Automatic if using system locale f.maximumSignificantDigits = 5; f.usesSignificantDigits = YES; // f.currencyCode = @"JPY"; // f.currencySymbol = @"¥"; if([f.locale.localeIdentifier hasPrefix:@"ja"]) { f.positiveFormat = @"#,##0¤"; if([f.currencyCode isEqualToString:@"JPY"]) // We allow ourselves this special case because *日本円 just looks dumb f.currencySymbol = @"円"; else f.currencySymbol = [f.locale displayNameForKey:NSLocaleCurrencyCode value:f.currencyCode]; } NSLog(@"%@",[f stringFromNumber:@1234567890]); NSLog(@"%@",[f stringFromNumber:@25]); } }