How do I convert a String to Double in Java using a specific locale?
Asked Answered
C

8

43

I want to convert some numbers which I got as strings into Doubles, but these numbers are not in US standard locale, but in a different one. How can I do that?

Clangor answered 20/5, 2009 at 14:1 Comment(1)
I have six answers, only two of them upvoted, but ALL of them are correct. The laurels go to the unabridged answer.Clangor
P
70

Try java.text.NumberFormat. From the Javadocs:

To format a number for a different Locale, specify it in the call to getInstance.

NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);

You can also use a NumberFormat to parse numbers:

myNumber = nf.parse(myString);

parse() returns a Number; so to get a double, you must call myNumber.doubleValue():

    double myNumber = nf.parse(myString).doubleValue();

Note that parse() will never return null, so this cannot cause a NullPointerException. Instead, parse throws a checked ParseException if it fails.

Edit: I originally said that there was another way to convert to double: cast the result to Double and use unboxing. I thought that since a general-purpose instance of NumberFormat was being used (per the Javadocs for getInstance), it would always return a Double. But DJClayworth points out that the Javadocs for parse(String, ParsePosition) (which is called by parse(String)) say that a Long is returned if possible. Therefore, casting the result to Double is unsafe and should not be tried!
Thanks, DJClayworth!

Parent answered 20/5, 2009 at 14:4 Comment(5)
Add the .doubleValue() method to the answer and I'll accept it.Clangor
I see nothing to promise that NumberFormat.parse() returns a Double. In fact it appears to say that if the value can be contained in a Long, it returns Long, causing your method 1 to throw a ClassCastExeption.Covetous
Be careful with French, because the FR_fr locale uses a non-breaking space (U+00A0) as the grouping separator. This causes the text to appear the same as if the separator were a "regular" space (U+0020) (e.g., standard keyboard space). The result is a silent failure where a number string that appears to be correctly formatted like "3 141,59" is parsed to 3 instead of 3141.59 . The string must be specified like "3\u00A0141,59" for it to parse correctly. Also, it's good practice to use the method with ParsePosition and check ParsePosition.getIndex() == inputString.length() after parsing.Finback
You might want to use "Locale.getDefault()", I wasted a couple of minutes before noticing why my "222,333" string was parsed as a "222" int.Kamseen
This also fails when the String is in scientific notation. For instance "1.93263561400442e-006" results into 1.93263561400442Papandreou
S
7

NumberFormat is the way to go, but you should be aware of its peculiarities which crop up when your data is less than 100% correct.

I found the following usefull:

http://www.ibm.com/developerworks/java/library/j-numberformat/index.html

If your input can be trusted then you don't have to worry about it.

Stratiform answered 20/5, 2009 at 14:17 Comment(1)
Could you summarize what was interesting in the link if you remember? It's broken now...Downcomer
W
6

Just learning java and programming. Had similar question. Found something like this in my textbook:

Scanner sc = new Scanner(string);
double number = sc.nextDouble();

The book says that a scanner automatically decodes what's in a String variabel and that the Scanner class automatically adapts to the language of the set Locale, system Locale being the default, but that's easy to set to something else.

I solved my problem this way. Maybe this could work for the above issue instead of parsing?

Addition: The reason I liked this method was the fact that when using swing dialouge boxes for input and then trying to convert the string to double with parse I got a NumberFormatException. It turned out that parse exclusively uses US-number formatting while Scanner can handle all formats. Scanner made the input work flawlessly even with the comma (,) decimal separator. Since the most voted up answer uses parse I really don't see how it would solve this particular problem. You would have to input your numbers in US format and then convert them to your locale format. That's rather inconvenient when ones numeric keybord is fitted with a comma.

Now you're all free to shred me to pieces ;)

Walkup answered 26/1, 2014 at 4:4 Comment(1)
The comments (in Android Studio at least) for java.util.Scanner are kind of funny... A parser that parses a text string of primitive types and strings with the help of regular expressions. This class is not as useful as it might seem. It's very inefficient for communicating between machines; you should use JSON, protobufs, or even XML for that. Very simple uses might get away with String#split. For input from humans, the use of locale-specific regular expressions make it not only expensive but also somewhat unpredictable.Netsuke
M
4

You use a NumberFormat. Here is one example, which I think looks correct.

Munford answered 20/5, 2009 at 14:6 Comment(0)
R
3

Use NumberFormat.getNumberInstance(Locale)

Reseat answered 20/5, 2009 at 14:7 Comment(0)
V
2

This should be no problem using java.text.DecimalFormat.

Volga answered 20/5, 2009 at 14:5 Comment(0)
O
1

Do you know which locale it is? Then you can use

DecimalFormat format = DecimalFormat.getInstance(theLocale);
format.parse(yourString);

this will even work for scientific notations, strings with percentage signs or strings with currency symbols.

Outguard answered 20/5, 2009 at 14:11 Comment(2)
DecimalFormat.getInstance is not guaranteed to return a DecimalFormat, actually. You're really calling NumberFormat.getInstance, which is only guaranteed to return a subclass of NumberFormat. From NumberFormat's docs: "If you want even more control over the format or parsing, or want to give your users more control, you can try casting the NumberFormat you get from the factory methods to a DecimalFormat. This will work for the vast majority of locales; just remember to put it in a try block in case you encounter an unusual one."Parent
You are right indeed. In my code, I actually use DecimalFormat format = (DecimalFormat)DecimalFormat.getInstance(theLocale); I didn't know it doesn't work for all locales...Outguard
K
-2

Here is how you use parseDouble to convert a String to a Double:

doubleExample.java

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader; 

public class doubleExample {

        public static void main(String[] args) {

                Double myDouble = new Double("0");
                System.out.println("Please enter a number:");

                try
                {
                        //get the number from console
                        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                        myDouble = Double.parseDouble(br.readLine());
                }
                //if invalid value was entered
                catch(NumberFormatException ne)
                {
                        System.out.println("Invalid value" + ne);
                        System.exit(0);
                }
    catch(IOException ioe)
                {
                        System.out.println("IO Error :" + ioe);
                        System.exit(0);
                }

                System.out.println("Double value is " + myDouble);
        }
}
Kenley answered 9/10, 2012 at 13:54 Comment(2)
What does your answer adds to previous accepted and high upvoted answers? Care to comment your code a bit?Zeitgeist
This answer is DOWNRIGHT INCORRECT. According to Java API documentation, parseDouble uses the same rules as valueOf, which are Java Language double format. That means it won't parse 1,0 as double, no matter the current locale. And, furthermore, there's no way to pass a specific locale, as asked for (which makes sense, since it doesn't use locale at all).Clangor

© 2022 - 2024 — McMap. All rights reserved.