Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force float value when using JSON.stringify

I want to force a Number to be a Float, after JSON.stringify(). Unfortunately JSON.stringify() deletes the 1 .0.

Example :

JSON.stringify(1.0) // "1"

Wanted outcome:

JSON.stringify(1.0) // "1.0"

I'm using an API which wants an object in JSON-Format, but it only understands decimal values. So I wanted to ask if it is possible using JSON.stringify to generate the string with decimal values without using Regex-.replace-magic

like image 403
Livio Brunner Avatar asked Dec 30 '16 16:12

Livio Brunner


3 Answers

Well for anyone wondering about the regex magic here it is: This is taken from stringify-with-floats npm library but modified to support any length of floats.

const beginFloat = "~begin~float~";
const endFloat = "~end~float~";

const stringifyWithFloats =
  (config = {}, decimals = 1) =>
  (inputValue, inputReplacer, space) => {
    const inputReplacerIsFunction = typeof inputReplacer === "function";
    let isFirstIteration = true;
    const jsonReplacer = (key, val) => {
      if (isFirstIteration) {
        isFirstIteration = false;
        return inputReplacerIsFunction ? inputReplacer(key, val) : val;
      }
      let value;
      if (inputReplacerIsFunction) {
        value = inputReplacer(key, val);
      } else if (Array.isArray(inputReplacer)) {
        // remove the property if it is not included in the inputReplacer array
        value = inputReplacer.indexOf(key) !== -1 ? val : undefined;
      } else {
        value = val;
      }
      const forceFloat =
        config[key] === "float" &&
        (value || value === 0) &&
        typeof value === "number" &&
        !value.toString().toLowerCase().includes("e");
      return forceFloat ? `${beginFloat}${value}${endFloat}` : value;
    };
    const json = JSON.stringify(inputValue, jsonReplacer, space);
    const regexReplacer = (match, num) => {
      return num.includes(".") || Number.isNaN(num)
        ? Number.isNaN(num)
          ? num
          : Number(num).toFixed(decimals)
        : `${num}.${"0".repeat(decimals)}`;
    };
    const re = new RegExp(`"${beginFloat}(.+?)${endFloat}"`, "g");
    return json.replace(re, regexReplacer);
  };

const test = {
  test: "test",
  float: 1.2,
  number: 1,
};

const formatted = stringifyWithFloats(
  { float: "float", number: "float" },
  2
)(test, null, 2); // null and 2 is just for pretty print

console.log(formatted);
like image 107
Chief koshi Avatar answered Oct 16 '22 18:10

Chief koshi


Use toFixed instead of stringify. Example:

var num = 1;
var numStr = num.toFixed(1); //result is "1.0"

More about toFixed - http://www.w3schools.com/jsref/jsref_tofixed.asp.

To be clear We are talking about conversion number to string not number to float ( such type not exists in javascript ) like can be understood from question description. toFixed will always return String with specified number of decimals.

like image 42
Maciej Sikora Avatar answered Oct 16 '22 19:10

Maciej Sikora


The straight and reasonably short answer to your question is no, you cannot customize the serialization of numeric values with JSON.stringify. See JSON.stringify() on MDN.

If you really need decimals for your integers you have to use "regex-magic" as you mention in your question or find a library allowing you to perform such tricks. If you aren't dealing with overly complex or many different kinds of objects you could probably stringify them manually.

As a sidenote, it sounds very, very suspicious with an API that needs to be fed with custom formatted JSON. I would tripple-check if there are any other way of using it.

like image 7
Carl-Evert Kangas Avatar answered Oct 16 '22 18:10

Carl-Evert Kangas