2009-12-25 66 views
0

經過了一天的這個問題,我會看看我是否可以得到一些幫助。這個問題之前或多或少有人問過,但似乎沒有人給出完整的答案,所以希望我們現在能夠得到答案。將NSString轉換爲貨幣 - 完整的故事

使用UILabel和UITextView(帶數字鍵盤)我想實現一種類似於ATM的行爲,讓用戶只需鍵入數字,並將其格式化爲標籤中的貨幣。這個想法基本上是這裏概述:

What is the best way to enter numeric values with decimal points?

唯一的問題是,它從來沒有明確地說,我們如何能夠從文本框具有類似於123的整數,爲$ 1.23 123¥等在標籤顯示去任何人都有這樣的代碼?

回答

3

我發現了一個解決方案,根據這個問題的目的,我將爲那些未來有這個問題的人提供一個完整的答案。首先,我創建了一個名爲NumberFormatting的新Helper類並創建了兩個方法。

// 
// NumberFormatting.h 
// Created by Noah Hendrix on 12/26/09. 
// 

#import <Foundation/Foundation.h> 


@interface NumberFormatting : NSObject { 

} 

-(NSString *)stringToCurrency:(NSString *)aString; 
-(NSString *)decimalToIntString:(NSDecimalNumber *)aDecimal; 

@end 

,這裏是執行文件:

// 
// NumberFormatting.m 
// Created by Noah Hendrix on 12/26/09. 
// 

#import "NumberFormatting.h" 


@implementation NumberFormatting 

    -(NSString *)stringToCurrency:(NSString *)aString { 
    NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init]; 
    [currencyFormatter setGeneratesDecimalNumbers:YES]; 
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 

    if ([aString length] == 0) 
     aString = @"0"; 

    //convert the integer value of the price to a decimal number i.e. 123 = 1.23 
    //[currencyFormatter maximumFractionDigits] gives number of decimal places we need to have 
    //multiply by -1 so the decimal moves inward 
    //we are only dealing with positive values so the number is not negative 
    NSDecimalNumber *value = [NSDecimalNumber decimalNumberWithMantissa:[aString integerValue] 
                   exponent:(-1 * [currencyFormatter maximumFractionDigits]) 
                   isNegative:NO]; 

    return [currencyFormatter stringFromNumber:value]; 
    } 

    -(NSString *)decimalToIntString:(NSDecimalNumber *)aDecimal { 
    NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init]; 
    [currencyFormatter setGeneratesDecimalNumbers:YES]; 
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 

    if (aDecimal == nil) 
     aDecimal = [NSDecimalNumber zero]; 

    NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithMantissa:[aDecimal integerValue] 
                   exponent:([currencyFormatter maximumFractionDigits]) 
                   isNegative:NO]; 

    return [price stringValue]; 
    } 

@end 

第一種方法,stringToCurrency,將採取的整數(在這種情況下,文本字段中傳遞),並使用它轉換爲十進制值根據用戶區域設置適當移動小數點。然後它返回一個使用NSNumberFormatter格式化爲貨幣的字符串表示。

第二種方法做了相反處理,它採用類似於1.23的值並使用類似的方法將其轉換回123。

下面是我如何使用它

... 
self.accountBalanceCell.textField.text = [[NumberFormatting alloc] decimalToIntString:account.accountBalance]; 
... 
[self.accountBalanceCell.textField addTarget:self 
              action:@selector(updateBalance:) 
            forControlEvents:UIControlEventEditingChanged]; 

在這裏,我們的文本字段的值設置爲從數據存儲十進制值,然後我們設置一個觀察者來監視更改文本的示例字段和運行的方法updateBalance

- (void)updateBalance:(id)sender { 
    UILabel *balanceLabel = (UILabel *)[accountBalanceCell.contentView viewWithTag:1000]; 
    NSString *value  = ((UITextField *)sender).text; 
    balanceLabel.text  = [[NumberFormatting alloc] stringToCurrency:value]; 
} 

哪個簡單地取文本字段值,並通過上述的方法stringToCurrency運行它。

對我來說,這看起來很駭人,所以請花一點時間查看並清理它,如果你有興趣使用它。另外我注意到它的大值破壞。

2

看看NSNumberFormatter,它將根據當前或指定的區域設置格式化數字數據。

+0

我特地到這一點,但它會採取123,並將其轉換爲$ 123.00當時的想法是將它轉換爲$ 1.23 – 2009-12-25 08:38:37

+0

也許你可以讀取字符串的長度,並考慮到語言環境,將其翻譯爲1.23(格式爲1.23),而不是123.00,格式爲123.00美元。 – 2009-12-25 09:25:38

+0

例如,您可以在語言環境的'NSNumberFormatter'上調用'-currencyDecimalSeparator'和'-currencyGroupingSeparator'來學習如何處理格式。 – 2009-12-25 09:41:50

0

由於我仍然沒有看到這個問題的正確答案,我將分享我的解決方案,而不使用NSScanner(掃描儀似乎不適用於我)。是這個「What is the best way to enter numeric values with decimal points?」和這個「Remove all but numbers from NSString」的答案。

首先,我提出一個的NSString與用戶的本地貨幣設置在一個的UITextField像這樣:

//currencyFormatter is of type NSNumberFormatter 
if (currencyFormatter == nil) { 
    currencyFormatter = [[NSNumberFormatter alloc] init]; 
    [currencyFormatter setLocale:[NSLocale currentLocale]]; 
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 
    //[currencyFormatter setGeneratesDecimalNumbers:YES]; 
    decimalSeperator = [currencyFormatter decimalSeparator]; //NSString 
    currencyScale = [currencyFormatter maximumFractionDigits]; //short 
    //[currencyFormatter release]; don't forget to release the Formatter at one point 

} 


//costField is of type UITextField 
NSDecimalNumber *nullValue = [NSDecimalNumber decimalNumberWithMantissa:0 exponent:currencyScale isNegative:NO]; 
[costField setText:[currencyFormatter stringFromNumber:nullValue]]; 

你可能會在viewControllers方法viewDidLoad中做到這一點:。 根據用戶設置,將顯示一個像這樣的字符串:$ 0.00(用於United Stated的本地設置)。根據您的情況,您可能希望從數據模型中提供一個值。

當用戶在文本域中的倒是我將提出一個鍵盤類型:

costField.keyboardType = UIKeyboardTypeDecimalPad; 

這可以防止用戶輸入任何東西,但數字。

在下面的UITextField的委託方法中,我將字符串分開以僅獲取數字(這裏我避免使用NSScanner)。這是可能的,因爲我知道在哪裏使用指定的前「currencyScale」值設置小數點分隔符:

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

if (textField == costField) { 

    //if for what ever reason ther currency scale is not available set it to 2 
    //which is the most common scale value 
    if (!currencyScale) { 
     currencyScale = 2; 
    } 

    // separate string from all but numbers 
    // https://stackoverflow.com/questions/1129521/remove-all-but-numbers-from-nsstring/1163595#1163595 
    NSString *aString = [textField text]; 
    NSMutableString *strippedString = [NSMutableString stringWithCapacity:10]; 
    for (int i=0; i<[aString length]; i++) { 
     if (isdigit([aString characterAtIndex:i])) { 
      [strippedString appendFormat:@"%c",[aString characterAtIndex:i]]; 
     } 
    } 

    //add the newly entered character as a number 
    // https://stackoverflow.com/questions/276382/what-is-the-best-way-to-enter-numeric-values-with-decimal-points/2636699#2636699 
    double cents = [strippedString doubleValue]; 
    NSLog(@"Cents:%f ",[strippedString doubleValue]); 
    if ([string length]) { 
     for (size_t i = 0; i < [string length]; i++) { 
      unichar c = [string characterAtIndex:i]; 
      if (isnumber(c)) { 
       cents *= 10;  //multiply by 10 to add a 0 at the end 
       cents += c - '0'; // makes a number out of the charactor and replace the 0 (see ASCII Table) 
      }    
     } 
    } 
    else { 
     // back Space if the user delete a number 
     cents = floor(cents/10); 
    } 

    //like this you could save the value as a NSDecimalNumber in your data model 
    //costPerHour is of type NSDecimalNumber 
    self.costPerHour = [NSDecimalNumber decimalNumberWithMantissa:cents exponent:-currencyScale isNegative:NO]; 

    //creat the string with the currency symbol and the currency separator 
    [textField setText:[currencyFormatter stringFromNumber:costPerHour]]; 

    return NO; 
    } 

return YES; 
} 

這樣,由用戶輸入的貨幣將永遠是正確的,也沒有必要檢查它。無論選擇哪種貨幣設置,這總是會導致格式正確的貨幣。

0

我真的不喜歡現有的答案,所以我結合了一些技巧。我用一個隱藏的UITextField和數字鍵盤輸入,並使用一個可見的UILabel進行格式化。

我得的是堅持一切特性:

@property (weak, nonatomic) IBOutlet UILabel *amountLabel; 
@property (weak, nonatomic) IBOutlet UITextField *amountText; 
@property (retain, nonatomic) NSDecimalNumber *amount; 

我有量和NSNumberFormatter爲高德:

NSDecimalNumber *amount_; 
NSNumberFormatter *formatter; 

設置我的格式在初始化:

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    self = [super initWithCoder:aDecoder]; 
    if (self) { 
     // Custom initialization 
     formatter = [NSNumberFormatter new]; 
     formatter.numberStyle = NSNumberFormatterCurrencyStyle; 
    } 
    return self; 
} 

下面是我用來驗證輸入的代碼將其轉換爲

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 
{ 
    NSString *asText = [textField.text stringByReplacingCharactersInRange:range withString:string]; 
    if ([asText length] == 0) { 
     [self setAmount:[NSDecimalNumber zero]]; 
     return YES; 
    } 
    // We just want digits so cast the string to an integer then compare it 
    // to itself. If it's unchanged then it's workable. 
    NSInteger asInteger = [asText integerValue]; 
    NSNumber *asNumber = [NSNumber numberWithInteger:asInteger]; 
    if ([[asNumber stringValue] isEqualToString:asText]) { 
     // Convert it to a decimal and shift it over by the fractional part. 
     NSDecimalNumber *newAmount = [NSDecimalNumber decimalNumberWithDecimal:[asNumber decimalValue]]; 
     [self setAmount:[newAmount decimalNumberByMultiplyingByPowerOf10:-formatter.maximumFractionDigits]]; 
     return YES; 
    } 
    return NO; 
} 

我有了這個二傳手比手柄格式化標籤,使完成按鈕:

-(void)setAmount:(NSDecimalNumber *)amount 
{ 
    amount_ = amount; 
    amountLabel.text = [formatter stringFromNumber:amount]; 
    self.navigationItem.rightBarButtonItem.enabled = [self isValid]; 
}