Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Given a number, say, -2982342342363.23425785 convert it to -2,982,342,342,363.23425785.

  • Extra points for not using look-behind

  • Extra points for not using regular expressions.

share|improve this question
1  
Why -2982,342,342,363.23425785 and not -2,982,342,342,363.23425785? –  Howard Jan 3 '12 at 8:40
    
typo. fixed :-) –  CamelCamelCamel Jan 3 '12 at 8:41
3  
How many extra points for not using look-behind and regexp? What is the objective winning criteria? –  user unknown Jan 4 '12 at 1:50
7  
It is a bit strange to tag the challenge as regular-expression and give extra points if not using them... –  PhiLho Jan 4 '12 at 9:25
2  
This is not [code-golf] - is it? –  user unknown Jan 6 '12 at 3:29

21 Answers 21

up vote 11 down vote accepted

Java, 50 chars

String C(double d){return String.format("%,f",d);}

Works as specified in most locales. Does the correct thing in all locales :)

Edit:

If you really want commas no matter the default locale, do:

String C(double d){return String.format(java.util.Locale.US,"%,f",d);}

which is 70 characters (60 if you've already imported java.util.*).

share|improve this answer
    
Thus you might need to set a US locale to comply to the spec... :-) –  PhiLho Jan 3 '12 at 15:37
    
Where does other locales differ? I remember vaguely a weird country that doesn't do the whole comma thing. –  CamelCamelCamel Jan 4 '12 at 13:37
1  
@Radagaisus: See en.wikipedia.org/wiki/Decimal_mark –  Ilmari Karonen Jan 4 '12 at 15:59

Spreadsheet, 6+dec.places chars 5 chars

Just enter the number in a cell with formatting #,##0.#########,##0. Works on OOo Calc and MS Excel. Couldn't quickly find something meaning "print as many decimal places as there are". That would shorten it a lot. Can use an int, so the problem is not anymore.

No look-behind, no regex.

share|improve this answer
1  
+1 These are my favourite kinds of answer. –  Griffin Mar 7 '12 at 16:57

Scala:

val l=List (12345.2345, 123456.2345, 1234567.2345, -12345.2345, -123456.2345, -1234567.2345)

def f(d: Double)={
val a=d.toString.split('.')
(if(d<0)"-"else"")+
a(0).toLong.abs.toString.reverse.sliding(3,3).mkString(",").reverse+"."+a(1)}

l.map(f)

144 chars without 1st and last line, but this isn't code golf, is it?. Imho no look behind and no regex used.

Result:

List(12,345.2345, 123,456.2345, 1,234,567.2345, -12,345.2345, -123,456.2345, -1,234,567.2345)
share|improve this answer
    
I haven't run this so I may be wrong, but won't it give an error if the given number has no decimal point (because a will only have 1 item so a(1) will be referencing a non-existent index)? –  Gareth Jan 4 '12 at 9:14
    
Since the number was not specified any further I assumed only numbers containing a decimal point, of different length and with and without negative sign. I did not consider pure Integers, hexadezimal notation, scientific notation (4.3e-23), numbers like '.4' or '-.4', '9.' or '-9.'. Numbers exceeding the range of Double aren't tested as well. However - since my function takes a Double as argument, an int-literal is implicitly converted to double, and f(4000) leads to 4,000.0 - but that is pure luck of mine. :) –  user unknown Jan 4 '12 at 15:37

Perl, regular expression

Using a regular expression and no look-behinds but look-aheads:

$v = "-2982342342363.23425785";
$v =~ s/\d(?=(\d{3})+(\.|$))/$&,/g;
print $v;

Each digit is replaced by itself plus a comma if it is followed by n digits where n is a multiple of three and immedetiately followed by a period or the end of the string.

share|improve this answer

Haskell, 105

f(a:b:c:n:s)|n/='-'=a:b:c:',':f(n:s)
f s=s
r=reverse
main=interact$uncurry((++).r.f.r).break(`elem`".\n")

This doesn't use regular expressions (obviously), but it does backtrack (namely, it reverses digits before adding separators).

share|improve this answer

Ruby 111 chars

parts = "-2982342342363.23425785".split('.')
parts[0].reverse.scan(/.{1,3}/).join(",").reverse + "." + parts[1]
share|improve this answer

PHP

Using the built in function for formatting numbers:

function format($number)
{
    $decimals=(strpos($number,'.')===false?0:strlen($number)-strpos($number,'.')-1);
    return number_format($number,$decimals,'.',',');
}

Doing it by hand:

function format($number)
{
    $parts=explode('.',$number);
    $temp="";
    $len=strlen($parts[0]);
    for($i=0;$i<$len;$i++)
    {
        if($i!=0 && $i%3==0)
        {
            $temp.=",".$parts[0][$len-$i-1];
        }
        else
        {
            $temp.=$parts[0][$len-$i-1];
        }
    }
    $parts[0]=strrev($temp);
    return implode('.',$parts);
}
share|improve this answer
    
That large for loop could probably be shortened a good bit if you use str_split. –  GigaWatt Jan 10 '12 at 22:33

PHP, 56

No Regex, no look-behind.

function f($n){return number_format($n).strstr($n,'.');}


My first attempts tried calculating how many decimals to keep in order to use it as the optional second parameter for number_format but I couldn't think of concise logic.

My second attempt treated the number as a string, splitting on ., then re-assembling it.

Then I realized I could just let number_format truncate for me, then re-append the decimal section (if any) with strstr.


A different version, not using number_format, in a total of 95 bytes:

function f($n){return strrev(implode(',',str_split(strrev(strtok($n,'.')),3))).strstr($n,'.');}

Longer and a bit more readable:

function f($num) {
    $right = strstr($num, '.');

    $left = strtok($num, '.');
    $left = str_split(strrev($left), 3);
    $left = strrev(implode(',', $left));

    return $left . $right;
}
share|improve this answer
    
No need for character counts, this hasn't been tagged as [code-golf]. str_split never even occurred to me. –  Gareth Jan 10 '12 at 22:45
    
Ah, kinda near here. Just assumed that because this was the codegolf stackexchange that everything was code golf. Oh well, it was good practice. –  GigaWatt Jan 10 '12 at 22:53
    
'Programming puzzles and Code Golf'. Not to worry, most people have made the same assumption on this question. :-) –  Gareth Jan 10 '12 at 22:56

vi, 25 chars

ebd0$F.99@='3hha,<C-V><ESC>'
0PZZ

The script moves the cursor to the last digit of the number, then tries to search backwards for a decimal point. From there (either the last digit, or the decimal point if there was one), the following process is executed 99 times: the cursor moves left 3 times, then attempts to move left again. If it was able to move left, then a comma is inserted; otherwise, the process aborts.

9 times is probably sufficient instead of 99, so this could be reduced to 18 24 characters.

EDIT: I realized that I wasn't accounting for possible edge cases with a negative sign in front, so I added six characters to deal with it. At the start, 'eb' will effectively move the cursor to the first digit of the number. 'd0' will delete everything before that (which is either the negative sign or nothing). Then at the end, '0' moves to the start of the line and 'P' inserts whatever was deleted earlier.

share|improve this answer

Python2 - 219

def c(s):
 c=str(s)
 i=max([k for k in range(len(c)) if c[k]=='.']+[-1])
 o=(c[i::] if i>0 else '')
 if i>0: c=c[:i]
 c=list(c);i=0;m={0:1,1:2,2:3,3:1}
 while len(c):
  o=c.pop()+(',' if i==2 else '')+o;i=m[i]
 return o

or I can do this...

Python2 - 112

def c(s):
 import locale
 locale.setlocale(locale.LC_ALL, 'en_US')
 return locale.format("%d", s, grouping=True)

Personally I like the first one more... mainly because of the map instead of logic hack. The second one is verbatim from StackOverflow of all places.

share|improve this answer

Python 2.7, 127/122 bytes

taking input from stndin:

n=`input()*1.0`.split('.')
s=''
k=0
for y in n[0][::-1]:
 s+=y;k+=1
 if k in range(0,len(n[0]),3):s+=','
print s[::-1]+'.'+n[1]

as a function:

def c(n):
 s='';k=0
 for y in`n*1.0`[0][::-1]:
  s+=y;k+=1
  if k in range(0,len(n[0]),3):s+=','
  return s[::-1]+'.'+n[1]

could probably be golfed more...

share|improve this answer

In Lua:

local lns =
{
"-2982342342363.23425785",
"-2982342342363",
"2982342342363",
"-.23425785",
".23425785",
"1",
"22",
"-333",
"4444.",
"333.333",
"puke",
}
local results = {} -- Find converted strings here
for i, ns in ipairs(lns) do
  local sign, digits, frac = string.match(ns, "^(%-?)(%d-)(%.%d*)$")
  if frac == nil then
    frac, sign, digits = '', string.match(ns, "^(%-?)(%d-)$")
  end
  if digits == nil or digits == '' then
    results[i] = ns -- Only a fractional part (or no numbers), leave unchanged
  else
    local groups = {}
    local v = 0 + digits
    while v > 0 do
      local g = math.fmod(v, 1000)
      table.insert(groups, 1, g)
      v = math.floor(v / 1000)
    end
    results[i] = sign .. table.concat(groups, ",") .. frac
  end
end

Odd mix of regular expressions and arithmetic... It allows to handle non-numbers, sign, etc. in a quite concise way. I need the two steps RE as they are quite limited in Lua.

[EDIT] I don't really comply to the requirement as I made an array of strings instead of an array of numbers. On the other hand, by default Lua is compiled with 32bit floats, not 64bit doubles, so the given number is truncated to the first digit after the decimal point... So Lua remains out of the competition. Oh well, it was fun to play with Lua again.

share|improve this answer
    
And technically speaking, those are Lua Patterns not RegEx :D –  Dalin Seivewright Jan 11 '12 at 18:10

num.replace(/(\d+)(\..*)?/, ($0,$1,$2) -> $1.replace(/(\d)(?=(\d{3})+$)/g,'$1,') + ($2 || ''))

This is in coffee script. There's no look behind in JavaScript, but you can pass a function to .replace(!). The first regex separates the string over the dot and the second regex deals only with the first part. It's a shorter way than using .split() and I had problems mimicking look-behind.

edit: changed to work in webkit browsers.

share|improve this answer

Python 3: 100 or 102 characters

100 characters as a function:

def f(s):n=(s+'.').find('.');return''.join((('-'in s)<i<n and i%3==n%3)*','+c for i,c in enumerate(s))

102 reading from stdin:

s=input();n=(s+'.').find('.');print(''.join((('-'in s)<i<n and i%3==n%3)*','+c for i,c in enumerate(s)))
share|improve this answer

Python (162 chars)

a=raw_input().split('.')
n=int(a[0])
a[0]=str(n%1000)
n=n/1000
while n>0:
    a[0]=str(n%1000)+','+a[0]
    n=n/1000
if len(a)>1:
    print a[0]+'.'+a[1]
else:
    print a[0]

Gah! New specs ruin this solution. Well for integer input

(89 chars)

n=int(raw_input())
s=str(n%1000)
n/=1000
while n>0:
    s=str(n%1000)+','+s
    n/=1000
print s

Will put up one for float later.

For float input

(152 97 chars)

n=float(raw_input())
s=str(n%1000)
n=int(n/1000)
while n>0:
    s=str(n%1000)+','+s
    n/=1000
print s
share|improve this answer

Python 2.7: 29 characters

A bit late to the party, but I just read about this new feature in 2.7 and figured this still deserves to be here:

f=lambda(n):'{:,f}'.format(n)

Used by calling f(-2982342342363.23425785) which returns "-2,982,342,342,363.234375". The error is due to floating-point precision: -2982342342363.23425785 gets represented as -2982342342363.234375.

share|improve this answer

C (99)

No regexes, no backtracking, not using built-in formatting of real numbers.

d=1000;f(x){x&&f(x/d)+printf("%d,",x%d);}main(x,y){scanf("%d.%d",&x,&y);f(x);printf("%c.%d",8,y);}
share|improve this answer

Q, 27 chars (integer input)

{(|:)","sv 3 cut (|:) -3!x}

q){(|:)","sv 3 cut (|:) -3!x}[23498723]

"23,498,723"

Q, 48 chars (float input)

{,[;".",a@1](|:)","sv 3 cut(|:)(*:)a:"."vs -3!x}

q){,;".",a@1","sv 3 cut(|:)(*:)a:"." vs -3!x}[234554.21434]

"234,554.21434"

share|improve this answer
    
@sinedcm suggested that you can get it down to 24 as {(|:)","sv 3 cut(|)($)x} –  Peter Taylor Mar 23 '12 at 19:48

Some JavaScript approaches:

(1) 74 characters but fails on some inputs, recursive creation:

function r(n){return n<0?"-"+r(-n):n<1e3?""+n:r(n/1e3-n/1e3%1)+","+n%1e3}

It has two failure channels: (1) if the substring contains subnumbers with leading 0's it sometimes will produce e.g. 1,10 instead of 1,010, and (2) I don't actually know if n/1000 - (n/1000)%1 always yields an integer. With bugs corrected the smallest I can get it is 130 characters:

function r(n,f){f=Math.floor;return n<0?"-"+r(-n):n%1?r(f(n))+(""+n).match(/\..*/)[0]:n<1e3?""+n:r(f(n/1e3))+","+(""+n).slice(-3)}

(2) Split over lookahead and join with commas, 95 characters, one statement:

m=(""+n).split('.'),m[0].split(/(?=(?:.{3})+$)/).join(",").replace("-,","-")+(m[1]?"."+m[1]:"")

I can't see a better way to handle negatives in this case.

(3) Array inserts every 3 characters to the left of the '.', 100 characters, uses a Bad Part of JS (n < 0 is true or false which coerce to 1 or 0 when used with <).

t=(""+n).split(""),i=t.indexOf('.');for(i=(i<0?t.length:i)-3;n<0<i;i-=3)t.splice(i,0,',');t.join("")
share|improve this answer

Ruby (didn't golf or count. No regexps.)

def commaize(n)
  a,b=((negative=n<0) ? -n : n).to_s.split('.')
  "#{negative ? '-':''}#{a.reverse.chars.each_slice(3).map(&:join).join(',').reverse}.#{b}"
end
share|improve this answer

COBOL

   ID DIVISION. 
   PROGRAM-ID. EDITNUM. 
   DATA DIVISION. 
   WORKING-STORAGE SECTION. 
   01  REALLY-BIG-NUMBER PIC --,---,---,---,--9.9(8). 
   PROCEDURE DIVISION. 
       MOVE -2982342342363.23425785 TO REALLY-BIG-NUMBER
       DISPLAY REALLY-BIG-NUMBER 
       GOBACK 
       . 

10 lines of code, of which six are mandatory. All the work is done by the MOVE statement, ably abetted by the data-definition.

The data-definition (01) uses a Picture-string to describe how the data is to be edited. Here, there will be a leading floating minus-sign, commas separating groups of three digits going left from (to-be-printed) decimal point. There are eight significant decimal places.

MOVE the value to the field, DISPLAY the field (if you want to see what the number looks like).

-2,982,342,342,363.23425785

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.