En mi experiencia, replaceAll (), como sugirió, es la mejor manera de hacer esto. No depende de la configuración regional actual, es simple y funciona.
Joonas Pulakka
1
@Marco Altieri: replaceAll(",",".")reemplaza todas las comas con puntos. Si no hay comas, entonces no hace nada. Double.valueOf()funciona (solo) con cadenas que usan punto como separador decimal. Nada aquí se ve afectado por la configuración regional predeterminada actual. docs.oracle.com/javase/8/docs/api/java/lang/…
Joonas Pulakka
44
El único problema replaceAll(",",".")es que solo funcionará si hay una coma: es decir: 1,234,567 arrojará java.lang.NumberFormatException: multiple points. Una expresión regular con anticipación positiva será suficiente p.replaceAll(",(?=[0-9]+,)", "").replaceAll(",", ".")Más en: regular-expressions.info/lookaround.html
artemisian
2
No hay ningún problema. NumberFormatException es bueno. ¿Cómo puede saber qué coma es la correcta? El formato es incorrecto y todo lo que puede hacer es mostrar un mensaje mejor legible que la excepción para el usuario.
El increíble Jan
2
@ TheincredibleJan No, el formato no es incorrecto. Algunos entornos locales usan comas como separador de miles, por lo que puede tener más de uno en un número y técnicamente sigue siendo una entrada válida.
Esto solo funciona si la configuración regional predeterminada actual utiliza una coma como separador decimal.
Joonas Pulakka
66
Para complicar aún más las cosas, algunos entornos locales usan comas como separador de miles , en cuyo caso "1,234" se analizaría a 1234.0 en lugar de arrojar un error.
Joonas Pulakka
17
El problema con NumberFormat es que ignorará silenciosamente los caracteres no válidos. Por lo tanto, si intenta analizar "1,23abc", felizmente devolverá 1,23 sin indicarle que la cadena entregada contenía caracteres que no se pueden analizar. En algunas situaciones, eso podría ser realmente deseable, pero no creo que sea el comportamiento deseado.
E-Riz
77
para TURQUÍA, debe usar NumberFormat.getInstance (new Locale (tr_TR))
Sí ... si no configuramos el separador de agrupamiento de mil y solo usamos el formato francés, un número en formato español (1.222.222,33) se convertirá a "1 222 222,33", que no es lo que quiero . ¡Así que gracias!
WesternGun
1
Otra cosa es que la configuración regional española no aparece como "predeterminada" y no puedo construir una Localecon el formato correcto new Locale("es", "ES")y luego analizar automáticamente la cadena de números con NumberFormat, ,como separador decimal y .como separador de mil grupos. Solo DecimalFormatfunciona.
WesternGun
¿Por qué no todos los países están disponibles allí? Me siento raro por usar el idioma francés para formatear números polacos ...
Línea del
18
Como señala E-Riz, NumberFormat.parse (String) analiza "1,23abc" como 1,23. Para tomar toda la entrada podemos usar:
... es muy rápido, ya que busca en la matriz de caracteres subyacente char-by-char. Las versiones de reemplazo de cadenas compilan un RegEx para evaluar.
Básicamente, reemplazar (char, char) es aproximadamente 10 veces más rápido y dado que harás este tipo de cosas en código de bajo nivel, tiene sentido pensar en esto. El optimizador de Hot Spot no lo resolverá ... Ciertamente no lo hace en mi sistema.
Este es el método estático que uso en mi propio código:
publicstaticdouble sGetDecimalStringAnyLocaleAsDouble (String value){if(value ==null){Log.e("CORE","Null value!");return0.0;}Locale theLocale =Locale.getDefault();NumberFormat numberFormat =DecimalFormat.getInstance(theLocale);Number theNumber;try{
theNumber = numberFormat.parse(value);return theNumber.doubleValue();}catch(ParseException e){// The string value might be either 99.99 or 99,99, depending on Locale.// We can deal with this safely, by forcing to be a point for the decimal separator, and then using Double.valueOf ...//http://stackoverflow.com/questions/4323599/best-way-to-parsedouble-with-comma-as-decimal-separatorString valueWithDot = value.replaceAll(",",".");try{returnDouble.valueOf(valueWithDot);}catch(NumberFormatException e2){// This happens if we're trying (say) to parse a string that isn't a number, as though it were a number!// If this happens, it should only be due to application logic problems.// In this case, the safest thing to do is return 0, having first fired-off a log warning.Log.w("CORE","Warning: Value is not a number"+ value);return0.0;}}}
¿Qué sucede si la configuración regional predeterminada es algo similar al alemán, donde una coma denota un lugar decimal? Podría pasar, por ejemplo, "1,000,000" que no se analizaría en la configuración regional alemana y luego sería reemplazado por "1,000,000" que no es un Double válido.
Eddie Curtis
Hola @jimmycar, acabo de actualizar mi respuesta para usar la versión actual de mi método estático. ¡Espero que esto resuelva tu problema! Pete
Pete
1
Por supuesto, debe usar la configuración regional correcta. Esta pregunta te ayudará.
En el caso de que no conozca la configuración regional del valor de cadena recibido y no sea necesariamente la misma configuración regional que la configuración regional predeterminada actual, puede usar esto:
Devolverá un doble sin importar cuál sea la configuración regional de la cadena. Y no importa cuántas comas o puntos haya. Por lo tanto, pasar 1,000,000.54funcionará, 1.000.000,54así que no tendrá que depender de la configuración regional predeterminada para analizar la cadena más. El código no está tan optimizado como puede ser, por lo que cualquier sugerencia es bienvenida. Traté de probar la mayoría de los casos para asegurarme de que resuelve el problema, pero no estoy seguro de que cubra todos. Si encuentra un valor de ruptura, hágamelo saber.
La pregunta inicial decía "¿Hay una mejor manera de analizar" 1,234 "para obtener 1,234 que: p = p.replaceAll (", ",". ");" , si cree que replacedifiere significativamente del uso replaceAll, explique por qué.
replaceAll(",",".")
reemplaza todas las comas con puntos. Si no hay comas, entonces no hace nada.Double.valueOf()
funciona (solo) con cadenas que usan punto como separador decimal. Nada aquí se ve afectado por la configuración regional predeterminada actual. docs.oracle.com/javase/8/docs/api/java/lang/…replaceAll(",",".")
es que solo funcionará si hay una coma: es decir: 1,234,567 arrojarájava.lang.NumberFormatException: multiple points
. Una expresión regular con anticipación positiva será suficientep.replaceAll(",(?=[0-9]+,)", "").replaceAll(",", ".")
Más en: regular-expressions.info/lookaround.htmlRespuestas:
Utilice java.text.NumberFormat :
fuente
Puede usar esto (la configuración regional en francés tiene
,
un separador decimal)O puede usar
java.text.DecimalFormat
y establecer los símbolos apropiados:fuente
Locale
con el formato correctonew Locale("es", "ES")
y luego analizar automáticamente la cadena de números conNumberFormat
,,
como separador decimal y.
como separador de mil grupos. SoloDecimalFormat
funciona.Como señala E-Riz, NumberFormat.parse (String) analiza "1,23abc" como 1,23. Para tomar toda la entrada podemos usar:
fuente
... es muy rápido, ya que busca en la matriz de caracteres subyacente char-by-char. Las versiones de reemplazo de cadenas compilan un RegEx para evaluar.
Básicamente, reemplazar (char, char) es aproximadamente 10 veces más rápido y dado que harás este tipo de cosas en código de bajo nivel, tiene sentido pensar en esto. El optimizador de Hot Spot no lo resolverá ... Ciertamente no lo hace en mi sistema.
fuente
Si no conoce la configuración regional correcta y la cadena puede tener mil separadores, este podría ser el último recurso:
Tenga en cuenta: esto felizmente analizará cadenas como "R 1 52.43,2" a "15243.2".
fuente
Este es el método estático que uso en mi propio código:
fuente
Por supuesto, debe usar la configuración regional correcta. Esta pregunta te ayudará.
fuente
En el caso de que no conozca la configuración regional del valor de cadena recibido y no sea necesariamente la misma configuración regional que la configuración regional predeterminada actual, puede usar esto:
Devolverá un doble sin importar cuál sea la configuración regional de la cadena. Y no importa cuántas comas o puntos haya. Por lo tanto, pasar
1,000,000.54
funcionará,1.000.000,54
así que no tendrá que depender de la configuración regional predeterminada para analizar la cadena más. El código no está tan optimizado como puede ser, por lo que cualquier sugerencia es bienvenida. Traté de probar la mayoría de los casos para asegurarme de que resuelve el problema, pero no estoy seguro de que cubra todos. Si encuentra un valor de ruptura, hágamelo saber.fuente
Esto haría el trabajo:
fuente
replace
difiere significativamente del usoreplaceAll
, explique por qué.