Search code examples
javascriptregexstring-formattingmoney-format

Format string number as currency


I would like a mask function to format number (as string) like a lot of mask plugins do.

Desired behavior:

format('1') // '0,01'
format('12') // '0,12'
format('123') // '1,23'
format('12345678') // '123.456,78'

It would be better if the formatter achieve this using only regex functions.

[EDIT]

A searched a lot of questions here in stackoverflow but mostly answers consist in add two decimal cases at the end of string. That's not what I expected.

EXPECTED:

format('1') // '0,01'
format('123') // '1,23'

NOT EXPECTED:

format('1') // '1,00'
format('123') // '123,00'

Solution

  • Here is a two-step solution: get the digits sorted into 3+ digit numbers and 1-2 digit numbers with

    ^(?:(\d+)(\d{2})|(\d{1,2}))$
    

    See the regex demo

    So, the numbers bigger than 1 will have their integer parts in Group 1 and decimal parts in Group 2, and Group 3 will hold all fractional numbers less than 0.

    Then, we check the number we get and only add thousand separators to the integer parts with

    .replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1.")
    

    See the JS demo:

    function format(s) {
      var re = /^(?:(\d+)(\d{2})|(\d{1,2}))$/; 
      if ((m = s.match(re)) !== null) {   
          if (m[3]) {                     // We have 1 or 2 digit number
              return m[3].length == 1 ? 
                  "0,0" + m[3] : "0," + m[3];
          } else {                       // We have a longer number
              return m[1].replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1.") + "," + m[2];
          }
        
        }
    }
    
    document.body.innerHTML = format('1') + "<br/>"; // '0,01'
    document.body.innerHTML += format('12') + "<br/>"; // '0,12'
    document.body.innerHTML += format('123') + "<br/>"; // '1,23'
    document.body.innerHTML += format('12345678') + "<br/>"; // '123.456,78'

    Actually, you may add the thousand and decimal separators as the function arguments:

    function format(str, thd, dec) {
      var re = /^(?:(\d+)(\d{2})|(\d{1,2}))$/; 
      if ((m = str.match(re)) !== null) {   
        if (m[3]) {                     // We have 1 or 2 digit number
          return m[3].length == 1 ? 
             "0" + dec + "0" + m[3] : "0" + dec + m[3];
        } else {                       // We have a longer number
             return m[1].replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1" + thd) + dec + m[2];
        }
      }
    }
    
    var thd = "."; // Thousand separator
    var dec = ","; // Decimal separator
    document.body.innerHTML = format('1', thd, dec) + "<br/>"; // '0,01'
    document.body.innerHTML += format('12', thd, dec) + "<br/>"; // '0,12'
    document.body.innerHTML += format('123', thd, dec) + "<br/>"; // '1,23'
    document.body.innerHTML += format('12345678', thd, dec) + "<br/>"; // '123.456,78'