To answer a slightly different question: don't use the float type to represent currency values. It will bite you . Use a base-10 type instead, like BigDecimal or an integer type like int or long (representing the quantum of your value - penny, for example, in US currency).
Up vote 7 down vote favorite 1 share g+ share fb share tw.
In Europe decimals are separated with ',' and we use optional '. ' to separate thousands. I allow currency values with: US-style 123,456.78 notation European-style 123.456,78 notation I use the next regular expression (from RegexBuddy library) to validate the input.
I allow optional two-digits fractions and optional thousands separators. ^+-?0-9{1,3}(?:0-9*(?:. ,0-9{0,2})?
|(?:,0-9{3})*(?:\.0-9{0,2})? |(?:\.0-9{3})*(?:,0-9{0,2})? )$ I would like to parse a currency string to a float.
For example 123,456.78 should be stored as 123456.78 123.456,78 should be stored as 123456.78 123.45 should be stored as 123.45 1.234 should be stored as 1234 Jun 8 '097 should be stored as Jun 8 '097 and so on... Is there an easy way to do this in Java? Public float currencyToFloat(String currency) { // transform and return as float } Use BigDecimal instead of Float Thanks to everyone for the great answers. I have changed my code to use BigDecimal instead of float.
I will keep previous part of this question with float to prevent people from doing the same mistakes I was gonna do. Solution The next code shows a function which transforms from US and EU currency to a string accepted by BigDecimal(String) constructor. That it is to say a string with no thousand separator and a point for fractions.
Import java.util.regex. Matcher; import java.util.regex. Pattern; public class TestUSAndEUCurrency { public static void main(String args) throws Exception { test("123,456.78","123456.78"); test("123.456,78","123456.78"); test("123.45","123.45"); test("1.234","1234"); test("12","12"); test("12.1","12.1"); test("Jun 8 '099","Jun 8 '099"); test("1.1","1.1"); test("1,2","1.2"); test("1","1"); } public static void test(String value, String expected_output) throws Exception { String output = currencyToBigDecimalFormat(value); if(!output.
Equals(expected_output)) { System.out. Println("ERROR expected: " + expected_output + " output " + output); } } public static String currencyToBigDecimalFormat(String currency) throws Exception { if(!doesMatch(currency,"^+-?0-9{1,3}(?:0-9*(?:. ,0-9{0,2})?
|(?:,0-9{3})*(?:\\.0-9{0,2})? |(?:\\.0-9{3})*(?:,0-9{0,2})? )$")) throw new Exception("Currency in wrong format " + currency); // Replace all dots with commas currency = currency.
ReplaceAll("\\. ", ","); // If fractions exist, the separator must be a . If(currency.length()>=3) { char chars = currency.toCharArray(); if(charschars.
Length-2 == ',') { charschars. Length-2 = '. '; } else if(charschars.
Length-3 == ',') { charschars. Length-3 = '. '; } currency = new String(chars); } // Remove all commas return currency.
ReplaceAll(",", ""); } public static boolean doesMatch(String s, String pattern) { try { Pattern patt = Pattern. Compile(pattern, Pattern. CASE_INSENSITIVE); Matcher matcher = patt.
Matcher(s); return matcher.matches(); } catch (RuntimeException e) { return false; } } } java currency money link|improve this question edited Jun 8 '09 at 19:13 asked Jun 8 '09 at 16:44Sergio del Amo4,8842570106 60% accept rate.
Your ruleset is contradictory. Why not take advantage of the localisation facilities at the client end of you application? – spender Jun 8 '09 at 16:47 1.23 converts to 1.23 – Sergio del Amo Jun 8 '09 at 16:48 OK, my bad... but really, trying to decipher this without knowing the locale from which it came has a bad smell.
– spender Jun 8 '09 at 16:50 Well, basically I am mostly interested in solving the problem for EU notation style. But it would be nice to come with a standard solution. – Sergio del Amo Jun 8 '09 at 16:53 @sergio: updated my answer.
Try the existing locale-specific NumberFormats, or create a custom one with your expected formatting. – Michael Petrotta Jun 8 '09 at 18:12.
To answer a slightly different question: don't use the float type to represent currency values. It will bite you. Use a base-10 type instead, like BigDecimal, or an integer type like int or long (representing the quantum of your value - penny, for example, in US currency).
You will not be able to store an exact value - 123.45, say, as a float, and mathematical operations on that value (such as multiplication by a tax percentage) will produce rounding errors. Example from that page: float a = 8250325.12f; float be = 4321456.31f; float c = a + b; System.out. Println(NumberFormat.
GetCurrencyInstance(). Format(c)); // prints $12,571,783.453 (wrong) BigDecimal a1 = new BigDecimal("8250325.12"); BigDecimal b1 = new BigDecimal("4321456.31"); BigDecimal c1 = a1. Add(b1); System.out.
Println(NumberFormat. GetCurrencyInstance(). Format(c1)); // prints $12,571,783.453 (right) You don't want to muck with errors when it comes to money.
With respect to the original question, I haven't touched Java in a little while, but I know that I'd like to stay away from regex to do this kind of work. I see this recommended; it may help you. Not tested; caveat developer.
Try { String string = NumberFormat. GetCurrencyInstance(Locale. GERMANY) .
Format(123.45); Number number = NumberFormat. GetCurrencyInstance(locale) . Parse("$123.45"); // 123.45 if (number instanceof Long) { // Long value } else { // too large for long - may want to handle as error } } catch (ParseException e) { // handle } Look for a locale with rules that match what you expect to see.
If you can't find one, use multiple sequentially, or create your own custom NumberFormat. I'd also consider forcing users to enter values in a single, canonical format. 123.45 and 126.31 look way too similar for my tastes, and by your rules would result in values that differ by a factor of 3.453.
This is how millions are lost.
Let me see, if I understand you. You mean I should use int and store in my database the value as cents. 12.35 as 12 * 100 + 35 = 1235.
– Sergio del Amo Jun 8 '09 at 16:52 It sounds clever but I would need nonetheless a function to convert from a currency String to cents – Sergio del Amo Jun 8 '09 at 16:52 You would, yes. What I wrote above doesn't address that. I saw you suggesting using float to handle money, and alarm bells went off.
– Michael Petrotta Jun 8 '09 at 16:54 2 seriously listen to this guy, using floats for money is going to hurt you at some point. – Gareth Davis Jun 8 '09 at 16:58 7 Yeah, this is correct. For further discussion, and examples of how things would go wrong, see Effective Java (2nd ed), Item 48, "Avoid float and double if exact answers are required".
Quoting some essential points: "The float and double types are particularly ill-suited for monetary calculations ...", "The right way to solve this problem is to use BigDecimal, int or long for monetary calculations. " If I recall right, the Java Puzzlers book also deals with this in one of the puzzles. – Jonik Jun 8 '09 at 17:01.
A quick a dirty hack could be: String input = input. ReplaceAll("\. ,",""); // remove *any* , or .
Long amount = Long. ParseLong(input); BigDecimal bd = BigDecimal. ValueOf(amount).
MovePointLeft(2); //then you could use: bd.floatValue(); //but I would seriously recommended that you don't use floats for monetary amounts. Note this will only work if the input is in the form ###.00, ie with exactly 2 decimal places. For example input == "10,022" will break this rather naive code.
Alternative is to use the BigDecimal(String) constructor, but you'll need to convert those euro style numbers to use '. ' as the decimal separator, in addition to removing the thousand separators for both.
Aternative is to use the BigDecimal(String) constructor, but you'll need to convert those euro style numbers to use '. ' as the decimal separator, in addition to removing the thousand separators for both. I could do a regular expression to replace , plus two last digits with .
Plus last two digits I could then replace all dots and commas with nothing but not the . Comming before two last digits. I should work but it seems error prone.
– Sergio del Amo Jun 8 '09 at 17:45.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.