iphone - decimals - Uso de NSNumberFormatter para obtener un valor decimal de una cadena de moneda internacional
nsnumberformatter() (7)
¿Ha intentado configurar la región en Francia en la configuración y luego intentar obtener la cantidad numérica para la cadena? O puede configurar manualmente el local del formateador de números con setLocale:
NSNumberFormatter utiliza la configuración regional que tiene para averiguar cuáles son los números de una cadena. Si solo necesita que el usuario pueda colocar una cadena de moneda localizada para su área, cambie el sistema a esa ubicación y luego haga una prueba. Si necesita que el usuario pueda poner múltiples formatos, a continuación, agregue algún tipo de sistema de selección para que sepa lo que están introduciendo.
Parece que el NSNumberFormatter no puede analizar las cadenas monetarias del euro (y probablemente otras) en un tipo numérico. ¿Puede alguien por favor demostrar que estoy equivocado?
Estoy intentando usar lo siguiente para obtener una cantidad numérica de una cadena de moneda:
NSNumberFormatter *currencyFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber *currencyNumber = [currencyFormatter numberFromString:currencyString];
Esto funciona bien para los montos en moneda británica y estadounidense. Incluso se ocupa de separadores de $ y £ y miles sin problemas.
Sin embargo, cuando lo uso con importes en euros (con el Formato de región establecido en Francia o Alemania en la aplicación de configuración), devuelve una cadena vacía. Todas las siguientes cadenas fallan:
12,34 €
12,34
12.345,67 €
12.345,67
Vale la pena señalar que estas cadenas coinciden exactamente con lo que sale del método stringFromNumber de NSNumberFormatter cuando se usa la configuración regional correspondiente.
Al establecer el Formato de región en Francia en la aplicación de configuración, luego establecer currencyNumber a 12.34 en el siguiente código, lo que hace que currencyString se configure en ''12, 34 € '':
NSNumberFormatter *currencyFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *currencyString = [currencyFormatter stringFromNumber:currencyNumber];
Obviamente, sería bastante fácil solucionar este problema específicamente para el euro, pero espero vender esta aplicación en la mayor cantidad de países posible y creo que una situación similar puede ocurrir con otras ubicaciones.
¿Alguien tiene una respuesta?
TIA, Duncan
Con la configuración predeterminada ( lenient
= NO), solo convertirá las cadenas en números si tienen el formato exacto de las cadenas que produce al formatear los números en cadenas.
Por lo tanto, en caso de que desee utilizar conversiones no indulgentes, debe tener en cuenta que en muchos entornos locales (¿todo?) Esto significa que los espacios en la cadena de entrada no deben interrumpirse ( /u00a0
). Esto es:
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];
Esto no producirá el resultado esperado, ya que la variable number
será nula. Para obtener el resultado deseado, use espacios sin interrupción en ambos lugares de la cadena (como separador de miles y separador de símbolo de moneda):
amount = @"10/u00a0000,00/u00a0€";
Entonces la conversión sucederá como se espera.
Por supuesto, si desea utilizar conversiones indulgentes, entonces esa es la forma más fácil de hacerlo, y probablemente sea la mejor opción para manejar la entrada humana.
Por otro lado, cuando se manejan datos generados por una máquina, una interpretación indulgente de las cadenas puede no ser deseable, ya que perderá la capacidad de verificar la exactitud de los datos de entrada.
Esta es una difícil. Haciendo los siguientes trabajos sin problemas:
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
Sin embargo, la salida del método /u00a0
devuelve la cadena /u00a0
, un espacio sin interrupciones , en lugar de lo esperado /u00a0
Las clases del formateador (así como las clases de expresiones regulares, entre otras) en OS X / iOS hacen uso de la biblioteca ICU , también utilizada por otros proyectos. Encontré al menos otros two informes de bug con respecto a este problema en particular. Parece que este es el comportamiento expected , sin embargo. (Pasé un tiempo buscando en la fuente de la UCI para encontrar dónde está definido, pero es un laberinto).
Mi recomendación, por el momento, sería pasar -setLenient:YES
al formateador de moneda. Tal vez incluso presentar un informe de error con el radar de Apple.
La forma de hacer esto en Swift es:
var locale = NSLocale.currentLocale()
var formatter = NSNumberFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US")
formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
var moneyDouble = formatter.numberFromString(textField.text)?.doubleValue
Asumiendo que textField.text es el número que se está ingresando.
Su código de trabajo en Swift ..
let formatter = NumberFormatter()
formatter.usesGroupingSeparator = true
formatter.locale = Locale(identifier: "de_DE")
formatter.numberStyle = NumberFormatter.Style.currency
formatter.string(from: NSNumber(floatLiteral: InputAsDoubleValue))!
Identificadores
- para alemán -
"de_DE"
- para EE.UU. -
"en_US"
- para Francia -
"fr_FR"
El valor formateado también se devolvería con el símbolo de moneda correspondiente.
Tengo una respuesta fea usando 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);
}
salida:
2011-05-05 12: 56: 25.460 ScannerTest [10882: 903] salida de flotador es 12.34
2011-05-05 12: 56: 25.473 ScannerTest [10882: 903] salida del flotador es 12.34
2011-05-05 12: 56: 25.474 ScannerTest [10882: 903] salida del flotador es 12345.67
2011-05-05 12: 56: 25.475 ScannerTest [10882: 903] salida del flotador es 12345.67
Verifiqué que (al menos en iOS 4.3) utilizando el indicador [formatter setLenient: YES] funcionó para mí con Euros. Sin ese conjunto de indicadores, el formateador no devuelve los valores correctos para Euros.