2010-08-24 10 views
20

Sembra che NSNumberFormatter non possa analizzare stringhe di valuta Euro (e probabilmente altre) in un tipo numerico. Qualcuno può per favore dimostrare che ho torto.Utilizzo di NSNumberFormatter per ottenere un valore decimale da una stringa di valuta internazionale

che sto tentando di utilizzare il seguente per ottenere una quantità numerica da una stringa di valuta:

NSNumberFormatter *currencyFormatter = [[[NSNumberFormatter alloc] init] autorelease]; 
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 
NSNumber *currencyNumber = [currencyFormatter numberFromString:currencyString]; 

Questo funziona bene per il Regno Unito e degli Stati Uniti importi in valuta. Si occupa anche di separatori $ e £ e migliaia senza problemi.

Tuttavia, quando lo uso con importi in valuta euro (con il formato della regione impostato su Francia o Germania nell'app delle impostazioni) restituisce una stringa vuota. Tutti i seguenti stringhe falliscono:

12,34 € 
12,34 
12.345,67 € 
12.345,67 

Vale la pena notare che queste stringhe corrispondono esattamente quello che viene fuori il metodo stringFromNumber del NSNumberFormatter quando si utilizza il locale corrispondente.

Impostazione del formato Regione per la Francia in app Impostazioni, quindi impostando currencyNumber al 12.34 nel seguente codice, si traduce in currencyString essere impostato '12, 34 €':

NSNumberFormatter *currencyFormatter = [[[NSNumberFormatter alloc] init] autorelease]; 
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 
NSString *currencyString = [currencyFormatter stringFromNumber:currencyNumber]; 

Sarebbe ovviamente abbastanza È facile aggirare questo problema specificamente per l'euro, ma spero di vendere questa app nel maggior numero possibile di paesi e penso che una situazione simile si verificherà con altri locali.

Qualcuno ha una risposta?

TIA, Duncan

+0

Non ho ancora trovato una soluzione, quindi qualsiasi input sarebbe molto apprezzato. Grazie, Duncan – pieSquared

+0

Suggerirei di presentare una segnalazione di errore. –

risposta

20

Questo è difficile. Facendo le seguenti opere senza problemi:

double moneyAmount = 1256.34; 
NSLocale *french = [[NSLocale alloc] initWithLocaleIdentifier:@"fr_FR"]; 
NSNumberFormatter *currencyStyle = [[NSNumberFormatter alloc] init]; 

[currencyStyle setLocale:french]; 
[currencyStyle setNumberStyle:NSNumberFormatterCurrencyStyle]; 
NSNumber *amount = [NSNumber numberWithDouble:moneyAmount]; 
NSString *amountString = [currencyStyle stringFromNumber:amount]; 

NSNumber *pAmount = [currencyStyle numberFromString:amountString]; // == 1256.34 

Tuttavia, l'output del metodo -currencyGroupingSeparator restituisce la stringa \u00a0, un non-breaking space, piuttosto che l'atteso ,.

Le classi di formattazione (oltre alle classi di espressioni regolari, tra le altre) su OS X/iOS utilizzano lo ICU library, utilizzato anche da altri progetti. Ho trovato almeno two altre relazioni bug riguardo a questo particolare problema. Sembra che questo sia il comportamento di expected, comunque. (Ho passato un po 'di tempo a setacciare la sorgente ICU per trovare dove è definito, ma è un labirinto.)

La mia raccomandazione, per il momento, sarebbe quella di passare -setLenient:YES al formattatore di valuta. Forse anche presentare un bug report con il radar di Apple.

+2

'setLenient:' is gold. –

2

Hai provato l'impostazione della regione in Francia nel impostazioni e poi il tentativo di ottenere l'importo numerico per la stringa? Oppure è possibile impostare manualmente il locale del formattatore di numeri con setLocale:. NSNumberFormatter utilizza qualsiasi localizzazione che ha per capire quali sono i numeri di una stringa. Se hai solo bisogno che l'utente sia in grado di inserire una stringa di valuta localizzata per la loro area, cambia il sistema in quella locale e poi prova. Se hai bisogno che l'utente sia in grado di inserire più formati, aggiungi una sorta di sistema di selezione in modo da sapere cosa stanno inserendo.

+0

Sì, tutto viene eseguito con le impostazioni internazionali corrette. Non ho bisogno di supportare più valute, basta lavorare con le stringhe nelle impostazioni locali native dell'utente. Quindi, nell'esempio sopra, le impostazioni internazionali sono impostate su Francia (o Germania, ecc.). Aggiornerò la domanda;) – pieSquared

1

Ho una risposta brutto usare NSScanner

NSArray * testStrings = [NSArray arrayWithObjects:@"12,34 €", @"12,34" ,@"12.345,67 €" ,@"12.345,67", nil]; 

    NSCharacterSet * charset = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; 

    for(NSString * s in testStrings) 
    { 
     s = [s stringByReplacingOccurrencesOfString:@"." withString:@""]; 
     s = [s stringByReplacingOccurrencesOfString:@"," withString:@"."]; 
     NSScanner * scanner = [NSScanner scannerWithString:s]; 
     [scanner setCharactersToBeSkipped:charset]; 
     float f; 
     [scanner scanFloat:&f]; 
     NSLog(@"float output is %.2f",f); 
    } 

uscita:
2011-05-05 12: 56: 25,460 ScannerTest [10882: 903] uscita galleggiante è 12.34
2011-05-05 12 : 56: 25.473 ScannerTest [10882: 903] output float è 12,34
2011-05-05 12: 56: 25.474 ScannerTest [10882: 903] output float è 12345.67
2011-05-05 12: 56: 25.475 ScannerTest [ 10882: 903] l'uscita float è 12345.67

+0

ottimo, lavoro per me. Risparmi il mio tempo :) – Dhaval

2

Ho verificato che (almeno su iOS 4.3) utilizzando il flag [formatter setLenient: YES] ha funzionato con me utilizzando Euro. Senza quel flag set, il formattatore non restituisce valori corretti per Euro.

0

Con le impostazioni predefinite (lenient = NO), convertirà le stringhe in numeri solo se sono formattati esattamente come le stringhe che produce durante la formattazione dei numeri in stringhe.

Quindi, nel caso in cui si vogliano utilizzare conversioni non clementi, è necessario tenere presente che in molte impostazioni locali (all?) Questo significa che gli spazi nella stringa di input devono essere non interrotti (\u00a0). Vale a dire:

NSString *amount = @"10 000,00 €"; 

NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; 
formatter.numberStyle = NSNumberFormatterCurrencyStyle; 

formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier: @"fr_FR"]; 

NSNumber *number = [currencyFormatter numberFromString: amount]; 

Questo non produrrà i risultati sperati, come variabile number sarà pari a zero. Per ottenere il risultato desiderato, utilizzare spazi non divisibili in entrambi i luoghi della stringa (come un separatore delle migliaia e un separatore di simbolo di valuta):

amount = @"10\u00a0000,00\u00a0€"; 

Poi la conversione avverrà come previsto.

Ovviamente, se si desidera utilizzare conversioni non volute, questa è la via più facile da percorrere e probabilmente sarà l'opzione migliore per gestire l'input umano.

D'altra parte, quando si gestiscono dati generati dalla macchina, un'interpretazione indulgente delle stringhe potrebbe non essere auspicabile in quanto si perde la possibilità di verificare la correttezza dei dati di input.

0

Il modo per farlo a Swift è:

var locale = NSLocale.currentLocale() 
    var formatter = NSNumberFormatter() 
    formatter.locale = NSLocale(localeIdentifier: "en_US") 
    formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle 

    var moneyDouble = formatter.numberFromString(textField.text)?.doubleValue 

Supponendo che il TextField.text è il numero viene immesso.

2

Il codice di lavoro in Swift ..

let formatter = NumberFormatter() 
    formatter.usesGroupingSeparator = true 
    formatter.locale = Locale(identifier: "de_DE") 
    formatter.numberStyle = NumberFormatter.Style.currency 
    formatter.string(from: NSNumber(floatLiteral: InputAsDoubleValue))! 

identificatori:

  • per tedeschi-"de_DE"
  • per US-"en_US"
  • per Francia - "fr_FR"

Il valore formattato sarebbe anche essere restituito con il rispettivo simbolo di valuta.

Problemi correlati