Spaces in number

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
feelixe
Prole
Posts: 36
Joined: Tue Aug 20, 2013 10:29 am

Spaces in number

Post by feelixe »

Hi! I've been thinking about a solution for this for i while but i can't come up with anything good. So, How do i format a number so there's spaces at every thousand. like this

68520 -> 68 520
1560340 -> 1 560 340


It's probably really simple but im stuck hehe. Thanks.
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: Spaces in number

Post by Nixola »

If you're sure the number is an integer you could do it so:

Code: Select all

function spacenumber(n) 
   local s = string.reverse(n)
   return s:gsub("(%d%d%d)", "%1 "):reverse() 
end

(not tested much)
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Spaces in number

Post by ivan »

For very large numbers you need to disable scientific notation (note, code would work with integers ONLY) so:

Code: Select all

function spaceinteger(n) 
   local s = string.format("%.0f",n):reverse()
   s = s:gsub("(%d%d%d)", "%1 "):reverse()
   return s:gsub("^(-?) ", "%1") -- dirty fix for leading space
end
For floating point numbers you need to specify how many digits after the decimal you would like:

Code: Select all

function spacenumber(n, d)
  d = d or 0
  local i, f = math.modf(n)
  local s = spaceinteger(i) 
  if d > 0 and not s:find("n") then
    f = math.abs(f)
    s = s .. "." .. string.format("%." .. d .. "f", f):sub(3)
  end
  return s
end
Alternative with pattern matching:

Code: Select all

function spacenumber(n, d)
  local s = string.format("%." .. (d or 0) .. "f", n)
  local n,i,f = s:match("^(-?)(%d*)(.*)$")
  i = i and (i:reverse():gsub("(%d%d%d)", "%1 "):reverse()) or ''
  i = i:gsub("^(-?) ", "%1")
  return (n or '') .. i .. (f or '')
end
PS. Further reading: http://lua-users.org/wiki/FormattingNumbers
PPS. Quick hack fix for negative numbers/leading space/nan and inf
Last edited by ivan on Mon Feb 22, 2016 3:38 pm, edited 15 times in total.
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Spaces in number

Post by zorg »

One possible algorithm that would work on floats would be: (in pseudocode)
- Get the number of "digits" (characters) that exist to the left of a dot (marking the decimal separator; messing with the lua locale may make this something else, though that's not really recommended)
- divide the above number by 3, and if it has a remainder, add one to it (and subtract 1, because we don't want an extra space before a number like "999")
- with a for loop starting at digitnum - floorednum and going to digitnum with an iteration step size of 3, insert a space each time until the loop terminates.
you got the number as a string, though this may not be the most efficient algorithm; one could try implementing this with string functions instead of a for loop.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Spaces in number

Post by ivan »

Zorg's version using string.sub (positive integers only):

Code: Select all

function spaceinteger(n) 
  local s = string.format("%.0f", n)
  local f = s:len()%3
  return s:sub(1, f) .. ' ' .. s:sub(f + 1):gsub("(%d%d%d)", "%1 ")
end
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Spaces in number

Post by zorg »

ivan wrote:Zorg's version using string.sub (positive integers only): (...)
Here's a potential negative-allowing, one-linered version of the above: (Though i did state that the algorithm could handle non-integers as well, but ivan's implementation can't, this one, however, can.)

Code: Select all

function spacenumber(n)
  local sign      = n >= 0 and '' or '-'
  local abs       = math.abs(n)
  local str       = string.format("%.18f", abs)
  local delimiter = str:find('%.')
  local prefix    = string.sub(str, 1, delimiter-1)
  local postfix   = string.sub(str, delimiter , -1)
  local len = prefix:len()%3; len = len > 0 and len or len-1
  return sign .. prefix:sub(1,len) .. prefix:sub(len+1):gsub("(%d%d%d)"," %1") .. postfix
end
return spacenumber(-10123456.52)
Edit: not perfect yet, since numbers that have 3 significant digits get duped. (e.g. 101.whatever becomes 101 101.whatever)
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Spaces in number

Post by airstruck »

Thought I'd take a crack at this.

Code: Select all

local function separate (n, sep)
    local prefix, suffix, previous = tostring(n):match '^(.%d*)(.*)$'
    local pattern, repl = '(%d)(%d%d%d%f[%D])', '%1' .. sep .. '%2'
    while prefix ~= previous do
        previous = prefix
        prefix = prefix:gsub(pattern, repl, 1)
    end
    return prefix .. suffix
end
Should work with negative and positive integers and fractional numbers. Shouldn't change special representations like scientific notation, "nan" and "infinity".

Algorithm is basically:

1 - Separate number into integer representation and fractional representation.
2 - In the integer representation, find a sequence of four digits not followed by another digit.
3 - If found, insert separator between first and second digits, update integer representation with the result, go to step 2.
4 - Else not found, return integer representation concatenated to fractional representation.

Here's a short solution that's not iterative.

Code: Select all

local function separate (n, sep)
    local s, i, f = tostring(n):match '^(%D?)(%d*)(.*)$'
    local p = (#i - 1) % 3 + 1
    return s .. i:sub(1, p) .. i:sub(p + 1):gsub('%d%d%d', sep .. '%1') .. f
end
The idea here is to skip 1 to 3 leading digits in the integral part, then put a separator before each run of three digits after that.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot], Google [Bot] and 237 guests