Java Forum / General / March 2006
Recovering formatted double
Richard F.L.R.Snashall - 21 Mar 2006 04:39 GMT In application code, I have code to format a double into a String:
double db = 12.34;
java.text.DecimalFormat fourdigits = new java.text.DecimalFormat( "0.0000" );
string db_in_string = " " + fourdigits.format( db );
and later, to recover the double:
double recovered_db;
try { recovered_db = Double.parseDouble( db_in_string ); } catch( NumberFormatException numberFormatException ) { // Generate error message ...
return; }
I have a client in another country, however, that is having trouble getting this code to function. Either they have to initiate overriding the locale with English, or hand-correct any values that are set (changing "," to ".", I believe).
How do I get this to function? It was my understanding that Double.parseDouble was locale insensitive and would trim any leading and trailing spaces.
Dimitri Maziuk - 21 Mar 2006 04:53 GMT Richard F.L.R.Snashall sez:
> In application code, I have code to format a double into > a String: [quoted text clipped - 30 lines] > Double.parseDouble was locale insensitive and would trim > any leading and trailing spaces. The obvious answer would be to pass around a Double instead of a String.
Dima
 Signature The speed at which a mistyped command executes is directly proportional to the amount of damage done. -- Joe Zeff
Richard F.L.R.Snashall - 21 Mar 2006 05:22 GMT > Richard F.L.R.Snashall sez: >> [quoted text clipped - 4 lines] > The obvious answer would be to pass around a Double instead > of a String. Not applicable. The string is sent to a user-modifiable text field and recovered later (if not modified, of course).
Dimitri Maziuk - 21 Mar 2006 18:30 GMT Richard F.L.R.Snashall sez:
>> Richard F.L.R.Snashall sez: >>> [quoted text clipped - 7 lines] > Not applicable. The string is sent to a user-modifiable text > field and recovered later (if not modified, of course). In which case you want to make sure you're printing it out in the default locale and reading it back in in the default locale. Probably using DecimalFormat for both printing and parsing.
IIRC Double.parseDouble() is pretty dumb: it won't read scientific notation and I don't think it'll trim whitespace either.
Dima
 Signature ...the mainstream products of major vendors largely ignore these demonstrated technologies... [Instead, their customers] are left with several ineffective solutions collected under marketing titles like "defense in depth". -- Thirty Years Later: Lessons from the Multics Security Evaluation
Stefan Ram - 21 Mar 2006 05:00 GMT >java.text.DecimalFormat fourdigits = >new java.text.DecimalFormat( "0.0000" ); You could fix the locale to a specific local such as »java.util.Locale.US« by using something like:
public class Main { public static void main( final java.lang.String[] args ) throws java.lang.Throwable { final java.text.NumberFormat numberFormat = java.text.NumberFormat.getInstance ( java.util.Locale.US ); numberFormat.setMinimumFractionDigits( 4 ); numberFormat.setMaximumFractionDigits( 4 ); final java.lang.String text = numberFormat.format( 1.2345 ); final double number = numberFormat.parse( text ).doubleValue(); java.lang.System.out.println( number ); }}
Thomas G. Marshall - 21 Mar 2006 05:12 GMT Stefan Ram said something like:
>> java.text.DecimalFormat fourdigits = >> new java.text.DecimalFormat( "0.0000" ); > > You could fix the locale to a specific local such as > »java.util.Locale.US« by using something like: That is not what he wants. If his code were to use the default locale:
NumberFormat nf = NumberFormat.getInstance(); // no param
Then the code would work properly no matter /where/ it was. If it were run in England, it would allow
3,14159
for example.
NOTE: I've said this a million times in the past. If you are formatting or parsing something that a user might enter, then you should always use NumberFormat (or a derivative).
You will never know when a user might enter in 1,000 for 1000, or any number of other digit grouping rules, many of which you might never guess at; they are that weird.
> public class Main > { public static void main( final java.lang.String[] args ) [quoted text clipped - 7 lines] > final double number = numberFormat.parse( text ).doubleValue(); > java.lang.System.out.println( number ); }}
 Signature "Realtor" and "realty" are pronounced "reel'-tor" and "reel'-tee", *not* "reel'-a-tor" and "reel'-i-tee" !!!! If you pronounce them with the extra syllable, you will sound like a complete idiot.
Richard F.L.R.Snashall - 21 Mar 2006 05:30 GMT > Stefan Ram said something like: > [quoted text clipped - 18 lines] > parsing something that a user might enter, then you should always use > NumberFormat (or a derivative). This is where I started to get lost. The manual page says the method is "static NumberFormat getInstance( )". Does that mean that the same static value is always passed back? If so, how do I then make my own copies? In the example I gave, I used four digits, but I also needed other numbers of digits.
If I may, another question; why not getNumberInstance, since my application is numeric only.
> You will never know when a user might enter in 1,000 for 1000, or any number > of other digit grouping rules, many of which you might never guess at; they > are that weird. Roedy Green - 21 Mar 2006 07:38 GMT On Mon, 20 Mar 2006 23:30:54 -0500, "Richard F.L.R.Snashall" <rflrs@notnotrcn.com> wrote, quoted or indirectly quoted someone who said :
>If I may, another question; why not getNumberInstance, since my >application is numeric only. just use new DecimalFormat
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Thomas G. Marshall - 23 Mar 2006 06:27 GMT Richard F.L.R.Snashall said something like:
>> Stefan Ram said something like: >> [quoted text clipped - 26 lines] > copies? In the example I gave, I used four digits, but I also needed > other numbers of digits. No, no, the format itself that you're using changes as you specify it. Ok, here's the way it was designed, which I'm not particularly thrilled with, but it's "eh, ok".
NumberFormat is an abstract class. It contains the factory methods for instantiating it's various subclasses.
The various getInstance() methods defined with NumberFormat (see some below) all call a private getInstance() which takes the desired locale and format style (see below as well). The private getInstance() employs a cache of number patterns. Don't ask me why this was considered so critical: I can't imagine that any of this would have been trouble without the cache.
I would avoid direct instantiation of the various number formats, however, only for maintainability reasons. Most coders are used to seeing one of the NumberFormat factory methods used...
> If I may, another question; why not getNumberInstance, since my > application is numeric only. More factory method hooey. Just getInstance() will be fine, it is equivalent.
Here, this is what the code actually looks like for those factory methods within NumberFormat (jdk 5.0). Note that NUMBERFORMAT is one of the "type" constants:
<elsewhere in NumberFormat.java> // Constants used by factory methods to specify a style of format. private static final int NUMBERSTYLE = 0; private static final int CURRENCYSTYLE = 1; private static final int PERCENTSTYLE = 2; private static final int SCIENTIFICSTYLE = 3; private static final int INTEGERSTYLE = 4; </elsewhere>
<factory methods> /** * Returns a general-purpose number format for the current default locale. * This is the same as calling * {@link #getNumberInstance() getNumberInstance()}. */ public final static NumberFormat getInstance() { return getInstance(Locale.getDefault(), NUMBERSTYLE); }
/** * Returns a general-purpose number format for the specified locale. * This is the same as calling * {@link #getNumberInstance(java.util.Locale) getNumberInstance(inLocale)}. */ public static NumberFormat getInstance(Locale inLocale) { return getInstance(inLocale, NUMBERSTYLE); }
/** * Returns a general-purpose number format for the current default locale. */ public final static NumberFormat getNumberInstance() { return getInstance(Locale.getDefault(), NUMBERSTYLE); }
/** * Returns a general-purpose number format for the specified locale. */ public static NumberFormat getNumberInstance(Locale inLocale) { return getInstance(inLocale, NUMBERSTYLE); } </factory>
..............more hooey..............and here is the private method I was talking about:
private static NumberFormat getInstance(Locale desiredLocale, int choice) { /* try the cache first */ String[] numberPatterns = (String[])cachedLocaleData.get(desiredLocale); if (numberPatterns == null) { /* cache miss */ ResourceBundle resource = LocaleData.getLocaleElements(desiredLocale ); numberPatterns = resource.getStringArray("NumberPatterns"); /* update cache */ cachedLocaleData.put(desiredLocale, numberPatterns); }
DecimalFormatSymbols symbols = new DecimalFormatSymbols(desiredLocale); int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice; DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols) ;
if (choice == INTEGERSTYLE) { format.setMaximumFractionDigits(0); format.setDecimalSeparatorAlwaysShown(false); format.setParseIntegerOnly(true); } else if (choice == CURRENCYSTYLE) { format.adjustForCurrencyDefaultFractionDigits(); }
return format; }
 Signature Everythinginlifeisrealative.Apingpongballseemssmalluntilsomeoneramsitupyournose.
Richard F.L.R.Snashall - 23 Mar 2006 06:57 GMT > Richard F.L.R.Snashall said something like:
> DecimalFormat format = new DecimalFormat(numberPatterns[entry], > symbols) > ; That's the first piece I was missing... the alternate formulation of the DecimalFormat constructor with the DecimalFormatSymbols... and then using a DecimalFormat method to parse the input as well, so the input format matched the output format.
Thomas Hawtin - 21 Mar 2006 19:55 GMT > Stefan Ram said something like: >> »java.util.Locale.US« by using something like: [quoted text clipped - 7 lines] > > 3,14159 We use comma as a thousand separator over here in the UK locale. So that, as in the US locale, is interpreted as 314,159.0.
In the UK, we do use a decimal point (a dot raised to the middle level of a digit character) as a decimal point. However, localisation tends to ignore that and go for what I assume is a vulgar Americanism.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Roedy Green - 21 Mar 2006 23:41 GMT On Tue, 21 Mar 2006 18:55:46 +0000, Thomas Hawtin <usenet@tackline.plus.com> wrote, quoted or indirectly quoted someone who said :
>In the UK, we do use a decimal point (a dot raised to the middle level >of a digit character) as a decimal point. However, localisation tends to >ignore that and go for what I assume is a vulgar Americanism. does localisation know about that?
One problem with implementing that is raised dot has less font support than period.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Roedy Green - 21 Mar 2006 07:37 GMT > You could fix the locale to a specific local such as > »java.util.Locale.US« by using something like: There are also DecimalFormat.setDecimalFormatSymbols to override the locale defaults:
But the easy way is to use a binary DataOutputStream which is locale-independent.
see http://mindprod.com/applets/fileio.html for sample code.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Richard F.L.R.Snashall - 21 Mar 2006 19:42 GMT >>java.text.DecimalFormat fourdigits = >>new java.text.DecimalFormat( "0.0000" ); [quoted text clipped - 13 lines] > final double number = numberFormat.parse( text ).doubleValue(); > java.lang.System.out.println( number ); }} I chose close to this:
// test version
final java.util.Locale myLocale = new java.util.Locale( "de" );
// final version
final java.util.Locale myLocale = java.util.Locale.getDefault( );
then, for formatting:
private java.text.NumberFormat digsFormat = java.NumberFormat.getInstance( myLocale );
and:
digsFormat.setMinimumFractionDigits( 1 ); digsFormat.setMaximumFractionDigits( 4 );
and finally:
db_in_string = digsFormat( db );
For recovery, I mimicked Double.parseDouble with another function:
public java.text.NumberFormat DFormat = java.text.NumberFormat.getInstance( myLocale ); public java.text.ParsePosition DPosition = new java.text.ParsePosition( 0 );
public double DparseDouble( String S ) throws NumberFormatException { String T = S.trim( ); DPosition.setIndex( 0 ); Number parsedNumber = DFormat.parse( T, DPosition );
if( DPosition.getIndex( ) < T.length( ) ) { throw new NumberFormatException( ); }
return parsedNumber.doubleValue( ); }
My thanks to all for your help.
Richard F.L.R. Snashall - 21 Mar 2006 23:55 GMT >>java.text.DecimalFormat fourdigits = >>new java.text.DecimalFormat( "0.0000" ); [quoted text clipped - 13 lines] > final double number = numberFormat.parse( text ).doubleValue(); > java.lang.System.out.println( number ); }} (My ISP may get around to sending the original of this later;-)
I chose close to this:
// test version
final java.util.Locale myLocale = new java.util.Locale( "de" );
// final version
final java.util.Locale myLocale = java.util.Locale.getDefault( );
then, for formatting:
private java.text.NumberFormat digsFormat = java.NumberFormat.getInstance( myLocale );
and:
digsFormat.setMinimumFractionDigits( 1 ); digsFormat.setMaximumFractionDigits( 4 );
and finally:
db_in_string = digsFormat( db );
For recovery, I mimicked Double.parseDouble with another function:
public java.text.NumberFormat DFormat = java.text.NumberFormat.getInstance( myLocale ); public java.text.ParsePosition DPosition = new java.text.ParsePosition( 0 );
public double DparseDouble( String S ) throws NumberFormatException { String T = S.trim( ); DPosition.setIndex( 0 ); Number parsedNumber = DFormat.parse( T, DPosition );
if( DPosition.getIndex( ) < T.length( ) ) { throw new NumberFormatException( ); }
return parsedNumber.doubleValue( ); }
My thanks to all for your help.
Richard F.L.R.Snashall - 22 Mar 2006 22:19 GMT > For recovery, I mimicked Double.parseDouble with another function: > [quoted text clipped - 16 lines] > return parsedNumber.doubleValue( ); > } Oops! It needs an additional check for a zero length trimmed string.
Filip Larsen - 21 Mar 2006 07:25 GMT > In application code, I have code to format a double into > a String. [...] > I have a client in another country, however, that is having > trouble getting this code to function. Use could your own DecimalFormat to format double string and use a NumberFormat.getNumberInstance() to parse it back in. Or perhaps better, round the double internally to the number of decimals you want and then use NumberFormat.getNumberInstance() to both format and parse the string.
Regards,
 Signature Filip Larsen
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|