views:

470

answers:

4

In Java, I need to add a thousands separator to a decimal number formatted as a String. However, I do not want a millions or billions separator... just a thousands separator with the existing fractional part of the number preserved.

9 == 9

999.999 == 999.999

9,999 == 9999

999999,999.999 == 999999999.999

I do not strictly need to use printf, but the conversion must be as fast as possible.

The input and output type must both be String.

Thanks!

+2  A: 

Firstly, this issue is not as simple as it appears since the thousand separator is not always a comma and is dependant on the user's Locale. In some cases it is actually a period, which may cause problems with any code you write for String manipulation.

If you wish to honour the user's Locale then a more considered approach is required, on the other hand, if you just want to take account of this one specific case and don't care about Locale settings then you could try something like this:

String s = "99999999.999";
s.replaceFirst("^(\\d+)(\\d{3})(\\.|$)", "$1,$2$3");
ninesided
Note also that if you want to be culture-sensitive, it's not a "thousands separator" but a "grouping separator", because some east asian cultures have it every 4th digit rather than ever 3rd.
Michael Borgwardt
I do not want to honor anyone's locale. It must always be a comma and it must always be in the place normally referred to as the thousands place in US English. The above Regex will not solve the issue because the fractional part of the decimal is not guaranteed to be 3. The preference is to have the fractional part be arbitrarily long.
Hamlet D'Arcy
This regex does not work for the input 9999, which returns 9999 instead of 9,999. FWIW, here is a test case: [ "" : "", "9" : "9","98" : "98", "987" : "987","987.6" : "987.6", "987.65" : "987.65","987.654" : "987.654", "987.6543" : "987.6543","9,876" : "9876", "98,765" : "98765","9876,543": "9876543", "9,876.5" : "9876.5","9,876.54": "9876.54", "9,876.543": "9876.543","98764321978654,321.987654321" : "98764321978654321.987654321",].each { expected, input ->assert expected == input.replaceFirst("(\\d)(\\d{3}\\.)", '$1,$2')}
Hamlet D'Arcy
I've updated the regex, this should properly handle all cases now.
ninesided
no, the unit test still fails. This time "987.6543" is converted to "987.6,543". -- insert pithy regex quote here --
Hamlet D'Arcy
here is the unit test in a web console: http://groovyconsole.appspot.com/script/61001
Hamlet D'Arcy
OK, so this time it _really_ works. Also checked against your Groovy console. Which is very groovy by the way.
ninesided
A: 

The best solution so far is:

return text.replaceFirst("^(\d+)(\d{3})(\.|$)", "$1,$2$3");

Hamlet D'Arcy
this doesn't work, you need to escape your slashes as in my example
ninesided
A: 

java.text.NumberFormat is what you need.

visit http://java.sun.com/j2se/1.4.2/docs/api/java/text/NumberFormat.html

Aadith
can people be so grateful as to explain why they give negative votes?
Aadith
A: 

def test='6816843541.5432' index = test.indexOf('.') test = test.substring(0,index - 3 ) + ',' + test.substring(index-3,test.size()) println test

Uxinn