Na minha experiência, replaceAll (), como você sugeriu, é a melhor maneira de fazer isso. Não depende da localidade atual, é simples e funciona.
Joonas Pulakka
1
@ Marco Altieri: replaceAll(",",".")substitui todas as vírgulas por pontos. Se não houver vírgulas, não fará nada. Double.valueOf()funciona (apenas) com cadeias que usam ponto como separador decimal. Nada aqui é afetado pela localidade padrão atual. docs.oracle.com/javase/8/docs/api/java/lang/…
Joonas Pulakka
4
O único problema replaceAll(",",".")é que só funcionará se houver uma única vírgula: ie: 1.234.567 será lançada java.lang.NumberFormatException: multiple points. A regex com antecipação positiva será suficiente p.replaceAll(",(?=[0-9]+,)", "").replaceAll(",", ".")Mais em: regular-expressions.info/lookaround.html
Artemisian
2
Não tem problema. O NumberFormatException é bom. Como você pode saber qual vírgula é a correta? O formato está errado e tudo o que você pode fazer é mostrar uma mensagem legível melhor que a exceção para o usuário.
O incrível
2
@TheincredibleJan Não, o formato não está errado. Alguns códigos de idioma usam vírgula como separador de milhares, para que você possa ter mais de um deles em um número e, tecnicamente, ainda é uma entrada válida.
Isso funciona apenas se o código do idioma padrão atual usar uma vírgula como separador decimal.
Joonas Pulakka
6
Para bagunçar ainda mais as coisas, alguns códigos de idioma usam vírgula como separador de milhares. Nesse caso, "1.234" seria analisado para 1234.0 em vez de gerar um erro.
Joonas Pulakka
17
O problema com NumberFormat é que ele ignorará silenciosamente caracteres inválidos. Portanto, se você tentar analisar "1,23abc", ele retornará 1,23 com prazer, sem indicar que a String passada continha caracteres não analisáveis. Em algumas situações, isso pode ser realmente desejável, mas não acho que esse seja o comportamento desejado.
E-Riz
7
Para a Turquia, você deve usar NumberFormat.getInstance (novo Locale (tr_TR))
Sim ... se não definirmos o separador de mil agrupamentos e usar apenas o formato francês, um número no formato espanhol (1.222.222,33) será convertido para "1 222 222,33", que não é o que eu quero . Então obrigado!
WesternGun 30/03
1
Outra coisa é que a localidade em espanhol não está listada como "padrão" e não posso construir um Localecom formato correto com new Locale("es", "ES")e, em seguida, analisar automaticamente a sequência numérica com NumberFormat, com ,o separador decimal e .o separador de mil grupos. Só DecimalFormatfunciona.
WesternGun
Por que nem todos os países estão disponíveis lá? Eu me sinto estranho sobre o uso de idioma francês para formatar números poloneses ...
Linha
18
Como E-Riz aponta, NumberFormat.parse (String) analisa "1,23abc" como 1,23. Para pegar toda a entrada, podemos usar:
... é muito rápido, pois pesquisa a matriz de caracteres subjacente, char a char. A cadeia substitui as versões compila um RegEx para avaliar.
Basicamente, substituir (char, char) é cerca de 10 vezes mais rápido e, como você fará esse tipo de coisa no código de baixo nível, faz sentido pensar nisso. O otimizador do Hot Spot não descobrirá ... Certamente não está no meu sistema.
Este é o método estático que eu uso no meu próprio 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;}}}
E se o Código de idioma padrão for algo como alemão, onde uma vírgula denota uma casa decimal? Você poderia passar, por exemplo, "1.000.000", que não seriam analisados na localidade alemã e depois seriam substituídos por "1.000.000", que não é um duplo válido.
Eddie Curtis
Oi @ jimmycar, Acabei de atualizar minha resposta para usar a versão atual do meu método estático. Espero que isso resolva o seu problema! Pete
Pete
1
Obviamente, você precisa usar o local correto. Esta pergunta vai ajudar.
No caso em que você não conhece o código de idioma do valor da string recebido e não é necessariamente o mesmo código de idioma que o código de idioma padrão atual, você pode usar isso:
Ele retornará um duplo, independentemente do local da string. E não importa quantas vírgulas ou pontos existam. Portanto, a passagem 1,000,000.54funcionará, 1.000.000,54assim você não precisará mais contar com o código do idioma padrão para analisar a sequência. O código não está tão otimizado quanto possível, portanto, todas as sugestões são bem-vindas. Tentei testar a maioria dos casos para garantir que ele resolvesse o problema, mas não tenho certeza de que ele cubra tudo. Se você encontrar um valor baixo, me avise.
A pergunta inicial dizia: "Existe uma maneira melhor de analisar" 1.234 "para obter 1.234 do que: p = p.replaceAll (", ",". ");" , se você acha que replacedifere significativamente do uso replaceAll, explique o motivo.
replaceAll(",",".")
substitui todas as vírgulas por pontos. Se não houver vírgulas, não fará nada.Double.valueOf()
funciona (apenas) com cadeias que usam ponto como separador decimal. Nada aqui é afetado pela localidade padrão atual. docs.oracle.com/javase/8/docs/api/java/lang/…replaceAll(",",".")
é que só funcionará se houver uma única vírgula: ie: 1.234.567 será lançadajava.lang.NumberFormatException: multiple points
. A regex com antecipação positiva será suficientep.replaceAll(",(?=[0-9]+,)", "").replaceAll(",", ".")
Mais em: regular-expressions.info/lookaround.htmlRespostas:
Use java.text.NumberFormat :
fonte
Você pode usar isso (o código de idioma francês possui
,
para separador decimal)Ou você pode usar
java.text.DecimalFormat
e definir os símbolos apropriados:fonte
Locale
com formato correto comnew Locale("es", "ES")
e, em seguida, analisar automaticamente a sequência numérica comNumberFormat
, com,
o separador decimal e.
o separador de mil grupos. SóDecimalFormat
funciona.Como E-Riz aponta, NumberFormat.parse (String) analisa "1,23abc" como 1,23. Para pegar toda a entrada, podemos usar:
fonte
... é muito rápido, pois pesquisa a matriz de caracteres subjacente, char a char. A cadeia substitui as versões compila um RegEx para avaliar.
Basicamente, substituir (char, char) é cerca de 10 vezes mais rápido e, como você fará esse tipo de coisa no código de baixo nível, faz sentido pensar nisso. O otimizador do Hot Spot não descobrirá ... Certamente não está no meu sistema.
fonte
Se você não souber o Local correto e a string puder ter um separador de milhar, esse pode ser o último recurso:
Esteja ciente: isso analisará felizmente cadeias de caracteres como "R 1 52.43,2" a "15243.2".
fonte
Este é o método estático que eu uso no meu próprio código:
fonte
Obviamente, você precisa usar o local correto. Esta pergunta vai ajudar.
fonte
No caso em que você não conhece o código de idioma do valor da string recebido e não é necessariamente o mesmo código de idioma que o código de idioma padrão atual, você pode usar isso:
Ele retornará um duplo, independentemente do local da string. E não importa quantas vírgulas ou pontos existam. Portanto, a passagem
1,000,000.54
funcionará,1.000.000,54
assim você não precisará mais contar com o código do idioma padrão para analisar a sequência. O código não está tão otimizado quanto possível, portanto, todas as sugestões são bem-vindas. Tentei testar a maioria dos casos para garantir que ele resolvesse o problema, mas não tenho certeza de que ele cubra tudo. Se você encontrar um valor baixo, me avise.fonte
Isso faria o trabalho:
fonte
replace
difere significativamente do usoreplaceAll
, explique o motivo.