Why does this "format thousands" function not format correctly with millions?

I have a function which takes a number and puts commas in between thousands. So 2389 for example would be formatted to 2,389.

local function formatThousands(num)
	local formatted, replacements = string.gsub(tostring(num), "^(-?%d+)(%d%d%d)", "%1,%2");
	return replacements < 1 and num or formatted;
end

I took this from Lua Users Formatting Numbers page and edited it a bit.

It seems to work fine for one thousands, ten thousands, hundred thousands, but it starts failing in the millions.

print(formatThousands(29999), formatThousands(2999999));

The output is:

29,999 2999,999

How can I fix this?

That page has this function:

function comma_value(amount)
  local formatted = amount
  while true do  
    formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
    if (k==0) then
      break
    end
  end
  return formatted
end

You’ll need to loop over your string with the same pattern until you can’t do any more replacements. Your edits to this were unnecessary.

EDIT: looking at the page again, there’s an even shorter (but more confusing) version of the function in a reply:

function comma_value(n) -- credit http://richard.warburton.it
	local left,num,right = string.match(n,'^([^%d]*%d)(%d*)(.-)$')
	return left..(num:reverse():gsub('(%d%d%d)','%1,'):reverse())..right
end
10 Likes

I am not sure about that function, but wouldn’t it be easier to just take a number, convert it to a string, and then add a comma after every 4th number?

You could use this too:

local Table = {__index = table}

function addCommas(str)
    str = str:reverse()

    local sections = setmetatable({}, Table)

    for section in str:gmatch '%d%d%d' do
        sections:insert(section)
    end

    local missingLen = #str - 3 * #sections
    if missingLen > 0 then
        sections:insert(str:sub(-1, -missingLen))
    end

    return sections:concat(','):reverse()
end

The problem with the code presented on the page is that you may need to call it multiple times, feeding the previous results into it, to get the desired end result when it wasn’t able to find any captures.

1 Like

If you’re referring to the comma_value function, you don’t need to call that multiple times.

Sorry, I meant his version of the function on that page :stuck_out_tongue:

1 Like

I avoided a loop because I thought it was unnecessary.

I just decided to go with the original thing in that page, and just modified it to fit my style. Thanks for your input.

(It worked)