如何在iOS上正确格式化货币

36

我正在寻找一种方法将字符串格式化为货币,而不使用TextField技巧。

例如,我想将数字"521242"转换为"5,212.42"。 或者,如果我有一个小于1美元的数字,我希望它看起来像这样:"52" -> "0.52"

谢谢

8个回答

67

你可能想要像这样做(假设currency是一个浮点数):

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
NSString *numberAsString = [numberFormatter stringFromNumber:[NSNumber numberWithFloat:currency]];
根据您的要求,将52视为.52,您可能需要除以100.0。
这种方法的好处在于它将遵循当前语言环境。因此,在适当的情况下,它会将示例格式化为“5.212,42”。
更新:我发布我的示例可能有点匆忙。如Conrad Shultz所指出的那样,在处理货币金额时,最好将数量存储为NSDecimalNumber。这将大大减少舍入误差带来的麻烦。如果您这样做了,上面的代码段将变为(假设currency是NSDecimalNumber*):
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
NSString *numberAsString = [numberFormatter stringFromNumber:currency];

31
不要使用浮点数来表示精确值(尤其是货币!),请使用NSDecimalNumber/NSDecimal。 - Conrad Shultz
1
@ConradShultz (+1) 很好的观点,但我倾向于避免这样的概括陈述。在十进制中可能完全可表示的事物很快就会变得不精确(例如,我拿你的“精确”数字除以三)。NSDecimalNumber/NSDecimal 的性能开销很快就会超过其好处。 - idz
2
@idz 当然 - 这就是为什么您需要一个处理这些情况的策略。但使用浮点数 一定会 在某个时候出问题,而且通常是在您最不希望出现问题的时候。当您处理货币时,每一分钱都很重要,浮点数是无法接受的。(顺便说一下,NSDecimalNumber非常轻量级;即使实时进行数千次计算,我也从未遇到过任何问题。) - Conrad Shultz
我的看法是:如果一个人正在构建一个仅计算估计值(而不是精确交易金额)的工具,那么浮点运算(例如双精度)可能是可以接受的。但是,了解权衡和后果是很重要的。 - Chris W. Rea
将资金转换为JSON的一个想法是使用分(或者你最小可分割单位),例如Square就是这样做的。这比在你的JSON中包含25.000001 Dollarpounds要好。 - Graham Perks
显示剩余2条评论

12

我使用这段代码。对我很有效。

1)将UITextField委托添加到头文件中

2)添加以下代码(启用ARC)

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

NSString *cleanCentString = [[textField.text
                              componentsSeparatedByCharactersInSet:
                              [[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
                             componentsJoinedByString:@""];
// Parse final integer value
NSInteger centAmount = cleanCentString.integerValue;
// Check the user input
if (string.length > 0)
{
    // Digit added
    centAmount = centAmount * 10 + string.integerValue;
}
else
{
    // Digit deleted
    centAmount = centAmount / 10;
}
// Update call amount value
NSNumber *amount = [[NSNumber alloc] initWithFloat:(float)centAmount / 100.0f];
// Write amount with currency symbols to the textfield
NSNumberFormatter *_currencyFormatter = [[NSNumberFormatter alloc] init];
[_currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[_currencyFormatter setCurrencyCode:@"USD"];
[_currencyFormatter setNegativeFormat:@"-¤#,##0.00"];
textField.text = [_currencyFormatter stringFromNumber:amount];
return NO; }

7
永远不要使用浮点数来表示精确值(尤其是货币金额)!应该使用NSDecimalNumber/NSDecimal。 - Conrad Shultz
1
如果硬编码除以100,如何确保例如日元的格式正确,因为日元没有像分一样的东西...请参考https://nshipster.com/nsformatter/上的“区域设置意识”。如果您将1000格式化为日元,则变为“¥1,000”。我真的必须维护一个映射表,其中包含每个支持的国家的除法因子,还是有NumberFormatter选项? - blackjacx

6

Swift 2.0版本:

    let _currencyFormatter : NSNumberFormatter = NSNumberFormatter()
    _currencyFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
    _currencyFormatter.currencyCode = "EUR"
    textField.text = _currencyFormatter.stringFromNumber(amount);

3
使用以下代码,它将解决您所有的问题...
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
NSString *numberAsString = [numberFormatter stringFromNumber:[NSNumber numberWithDouble:[currency doubleValue]]];

2
这是我使用NSDecimalNumbers重新制作AAV答案时发现的内容。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

NSString *cleanCentString = [[textField.text
                              componentsSeparatedByCharactersInSet:
                              [[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
                             componentsJoinedByString:@""];


// Parse final integer value
NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithMantissa:[cleanCentString integerValue]
                                                           exponent:-2
                                                         isNegative:NO];

NSDecimalNumber *entry = [NSDecimalNumber decimalNumberWithMantissa:[string integerValue]
                                                           exponent:-2
                                                         isNegative:NO];

NSDecimalNumber *multiplier = [NSDecimalNumber decimalNumberWithMantissa:1
                                                            exponent:1
                                                          isNegative:NO];

NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
                                                                                         scale:2
                                                                              raiseOnExactness:NO
                                                                               raiseOnOverflow:NO
                                                                              raiseOnUnderflow:NO
                                                                           raiseOnDivideByZero:NO];
NSDecimalNumber *result;

// Check the user input
if (string.length > 0)
{
    // Digit added
    result = [price decimalNumberByMultiplyingBy:multiplier withBehavior:handler];
    result = [result decimalNumberByAdding:entry];
}
else
{
    // Digit deleted
    result = [price decimalNumberByDividingBy:multiplier withBehavior:handler];
}

// Write amount with currency symbols to the textfield
NSNumberFormatter *_currencyFormatter = [[NSNumberFormatter alloc] init];
[_currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[_currencyFormatter setCurrencyCode:@"USD"];
textField.text = [_currencyFormatter stringFromNumber:result];

return NO;
}

1
func getCurrencyFormat(price:String)->String{
    let convertPrice = NSNumber(double: Double(price)!)
    let formatter = NSNumberFormatter()
    formatter.numberStyle = .CurrencyStyle
    formatter.currencyCode = "USD"        

    let convertedPrice = formatter.stringFromNumber(convertPrice)       
    return convertedPrice!
}

注意:货币代码是由三个字母组成的代码,大多数情况下,它由一个国家的两个字符的互联网国家代码加上一个额外的字符来表示货币单位。例如,澳大利亚元的货币代码为“AUD”。

1
对于经过测试的Swift代码(引用自AAV的代码)
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool{

    let strMain : NSString = string

    let arrTemp : NSArray = (textField.text?.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))!
    let str: NSString = arrTemp.componentsJoinedByString("")

    //NSInteger centAmount = cleanCentString.integerValue;
    var centAmount : NSInteger = str.integerValue

    if (string.length > 0)
    {
        // Digit added
        centAmount = centAmount * 10 + strMain.integerValue;
    }
    else {
        // Digit deleted
        centAmount = centAmount / 10;
    }

    let amount = (Double(centAmount) / 100.0)

    let currencyFormatter = NSNumberFormatter()
    currencyFormatter.numberStyle = .CurrencyStyle
    currencyFormatter.currencyCode = "USD"
    currencyFormatter.negativeFormat = "-¤#,##0.00"
    let convertedPrice = currencyFormatter.stringFromNumber(amount)

    print(convertedPrice)

    txtAmount.text = convertedPrice! //set text to your textfiled
    return false //return false for exact out put
}

注意:如果您想从输入中删除默认的货币符号,可以将currencySymbol用空白填充,如下所示。
currencyFormatter.currencyCode = nil
currencyFormatter.currencySymbol = ""

愉快的编程!


0
使用格式化程序的一个问题是它们创建起来很昂贵。最好每个视图或视图控制器只创建一次。使用lazy是避免这种开销的完美解决方案。这也将许多样板代码移到主要代码之外,使其更加简洁明了。
class MyViewController: UIViewController {
    @IBOutlet var priceLabel: UILabel!

    private lazy var currencyFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.currencySymbol = "$"
        formatter.numberStyle = .currency
        return formatter
    }()

     // rest of class
 }

如先前所述,使用 Decimal 表示货币最佳,而 Double 则只是近似值。

priceLabel.text = currencyFormatter.string(for: Decimal(9.48))

输出:

$9.48

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接