1

I am using javascript and I've seen some ways to convert a currency to a number, but not one that is flexible to understand multiple input formats (decimal separator changes based on the user preference).

Let me show what I mean:

Some possible inputs (String or Number):

  • "1.000,50"
  • "$1.000,50"
  • "1,000.50"
  • "$1,000.50"
  • 1000.50

Output (Number):

  • 1000.50
4
  • 7
    How will you know whether 1,505 is intended to be an integer number or a number with decimals?
    – trincot
    Commented Apr 3 at 19:39
  • 1
    Please take the tour. Questions like this one that do not show that the author has tried to create a solution by showing their work are not considered to be good questions. Commented Apr 3 at 19:42
  • Also see How to Ask.
    – isherwood
    Commented Apr 3 at 20:02
  • Thank you all. I'll indeed need to make sure the string/number has no more than 3 places after the separator. Commented Apr 5 at 12:20

3 Answers 3

2

You can check if the input is a number or a string. If it is a number, return it immediately. If it is a string, detect the number format and replace characters as necessary, and return the converted number.

const inputs = [
  "1.000,50",
  "$1.000,50",
  "1,000.50",
  "$1,000.50",
  1000.50,
  "-$1,000.50",
  "-1,000.50",
  10005e-1
];
const expected = 1000.50;

const convert = (input) => {
  if (typeof input === 'number') return input; // Pass-through
  if (typeof input !== 'string')
    throw new Error(`Expected number or string for '${input}' (${typeof input})`);
  const stripped = input.replace(/[^\d.,-]/g, '')
  return stripped.slice(-3).includes(',')
    ? +stripped.replace(/\./g, '').replace(/,/g, '.') // e.g. French format
    : +stripped.replace(/\,/g, '');                   // e.g. US format
};

// true
console.log(inputs.every(input => {
  const actual = convert(input);
  console.log(`${input} -> ${actual}`);
  return Math.abs(Math.abs(actual) - expected) < 0.000001;
}));
.as-console-wrapper { top: 0; max-height: 100% !important; }

Here is a more-robust solution that checks for NaN as well:

const inputs = [
  "1.000,50",
  "$1.000,50",
  "1,000.50",
  "$1,000.50",
  1000.50
];
const expected = 1000.50;

const stripNonNumericCharacters = (input) => input.replace(/[^\d.,-]/g, '');

const isFrenchFormat = (stripped) => stripped.slice(-3).includes(',');

const convertToNumber = (stripped, frenchFormat) => {
  return frenchFormat
    ? parseFloat(stripped.replace(/\./g, '').replace(/,/g, '.'))
    : parseFloat(stripped.replace(/,/g, ''));
};

const convert = (input) => {
  if (typeof input === 'number') return input; // Pass-through
  if (typeof input !== 'string')
    throw new Error(`Expected number or string for '${input}' (${typeof input})`);
  const stripped = stripNonNumericCharacters(input);
  const frenchFormat = isFrenchFormat(stripped);
  const parsed = convertToNumber(stripped, frenchFormat);
  if (isNaN(parsed)) {
    throw new Error(`Invalid number format for '${input}'`);
  }
  return parsed;
};

// true
console.log(inputs.map(convert).every(actual => Math.abs(actual - expected) < 0.000001));
.as-console-wrapper { top: 0; max-height: 100% !important; }

3
  • You should add support for negative numbers :P
    – Bergi
    Commented Apr 3 at 21:08
  • As well as supporting negative currency, you may also want to consider supporting fractional currency. After all typeof -3.1415e-27 === number Commented Apr 3 at 21:20
  • 1
    @Bergi I added a hyphen to the regex. Commented Apr 4 at 14:10
0

In the snippet below I'm copying the String that you have, ignoring $ and, if it's . or , then I'm ignoring it unless it's at the end of the String.

let tests = [
    "1.000,50",
    "$1.000,50",
    "1,000.50",
    "$1,000.50",
    1000.50,
    "-$1,000.50"
]

console.log(tests.map(item => {
    if (!isNaN(item)) return item;
    let newItem = "";
    for (let index = 0; index < item.length; index++) {
        if (item[index] !== "$") {
            let dotcomma = [".", ","].indexOf(item[index]);
            if ((dotcomma >= 0) && (index >= item.length - 3)) {
                newItem += ".";
            } else if (dotcomma < 0) {
                newItem += item[index];
            }
        }
    }
    return parseFloat(newItem);
}));

0

For this I Found this Solutions lets try

let tests = [
"1.000,50",
"$1.000,50",
"1,000.50",
"$1,000.50",
1000.50,
"-$1,000.50"
]

 for (let index = 0; index < tests.length; index++) {
    const element = tests[index];
   
  if(typeof(element)== 'string'){
   )
  let numstr= element.replace(",", "");

if(isNaN(numstr[0])){

      numstr = numstr.slice(1)
        if(isNaN(numstr[0])){
         numstr = numstr.slice(1)
          numstr = parseFloat(numstr)
       tests[index] = numstr
        }else{
           numstr = parseFloat(numstr)
       tests[index] = numstr
        }
    
   }else{
   /* numstr = numstr.slice(1) */
   
      numstr = parseFloat(numstr)
       tests[index] = numstr
     }
   }  


   }
  console.log(tests)

output : [1.0005, 1.0005, 1000.5, 1000.5, 1000.5, 1000.5]

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