ZiiMakc
ZiiMakc

Reputation: 36856

How to check if string/number is SIMPLE number

In most cases for me, i just want to check if string/number that i get is simple number only like this:

0, 1, 500, -1, 1.1, -1.1, 1.1013200 and so on.

And then convert it safely, without getting unexpected results.

What will be correct way to check if string or number is SIMPLE number?

Simple stands for:

  1. No scientific notations like "1e+30"
  2. No spaces like " 1"
  3. No ".1" or "080" and notations like this
  4. Limit to length that js can handle, convert to and from with same result
  5. Other stuff that i could forget

Codesandbox.

Upvotes: 0

Views: 368

Answers (5)

R3tep
R3tep

Reputation: 12864

You can parse it to number and parse this number to String another time. After test if the two variables is the same.

For scientific notations you can check if the string includes "e" or includes "NaN" for NaN number

Like :

var num_s = " 898";
var num_n = Number(num_s)

var num2_s = "89.8";
var num2_n = Number(num2_s)

var num3_s = "1e+23";
var num3_n = Number(num3_s)

var num4_s = "NaN";
var num4_n = Number(num4_s)

console.log(num_s === String(num_n))
console.log(num2_s === String(num2_n))
console.log(num3_s === String(num3_n) && !num3_s.includes('e'))
console.log(num4_s === String(num4_n) && !num4_s.includes('NaN'))

You can create a function that test this cases like

function isSimpleNumber(num_s) {
  var num_n = Number(num_s)
  if (Number.isNaN(num_n) || num_n > Number.MAX_SAFE_INTEGER || num_n < Number.MIN_SAFE_INTEGER) 
    return false;
  return num_s === String(num_n) && !num_s.includes('e');
}

Upvotes: 1

ZiiMakc
ZiiMakc

Reputation: 36856

Thanks to @Vlaz and R3tep i combined a function to make it work, only problem is .1 values, but cannot see a way to check it and they converted to and from without problems, it's ok.

Codesandbox.

const isSimpleNum = n => {
  const nStr = String(n);
  const nNum = Number(n);

  if (nStr === "-0") return true;

  if (nNum > Number.MAX_SAFE_INTEGER || nNum < Number.MIN_SAFE_INTEGER)
    return false;

  if (nStr === String(nNum) && !["e", "NaN"].some(e => nStr.includes(e))) {
    return true;
  } else {
    return false;
  }
};

const isTrue = ["1", "-1", 1, -1, 0, -0, "0", "-0", 1.1, -0.1, "0.1", "-0.1"];
const isFalse = [
  "-0,1",
  "080",
  0.1,
  ".1",
  " 898",
  "a",
  "1e+23",
  "NaN",
  undefined,
  null,
  NaN,
  Infinity
];

isTrue.forEach((v, i) => {
  if (!isSimpleNum(v)) {
    console.log(`isTrue index ${i} as ${v} not passed`);
  }
});
console.log("isTrue done");

isFalse.forEach((v, i) => {
  if (isSimpleNum(v)) {
    console.log(`isFalse index ${i} as ${v} not passed`);
  }
});
console.log("isFalse done");

Upvotes: 1

VLAZ
VLAZ

Reputation: 28997

A somewhat "dumb" solution but you can convert the input to a number and check if it looks like the input again:

function canSafelyConvert(input) {
  //convert to number
  const numeric = Number(input);
  
  //cannot convert
  if (Number.isNaN(numeric)) 
    return false;
    
  //discard values that are going to cause problems
  if (numeric > Number.MAX_SAFE_INTEGER || numeric < Number.MIN_SAFE_INTEGER) 
    return false;
  
  let canonicalValue = input;
  
  if(canonicalValue.includes(".")) {
    //remove trailing zeries and the decimal dot, if nothing is left after it
    canonicalValue = canonicalValue.replace(/\.?0+$/g, "")
  }
   
  //check if the converted value seems the same as the input
  return String(numeric) === canonicalValue;
}

const testValues = [
  //valid
  "0",
  "1",
  "1.000",
  "500",
  "-1",
  "1.1",
  "-1.1",
  "1.1013200",
  
  //invalid
  "1e+30",
  " 1",
  "080",
  ".1"
]

for (const value of testValues) {
  console.log(value, ":",  canSafelyConvert(value));  
}

This will filter out any values that are different when converted to a JavaScript numeric.

  1. If a value simply cannot be converted, then NaN would be produced and you can safely discard the output.
  2. If the value is too small or too large, then it can be discarded as it's not going to be safe to use.
  3. If the output seems OK, then you can compare it to the input again. You have to strip trailing zeroes after the decimal, since 1.2000 will be converted to 1.2. You also have to strip a dangling decimal dot for the case where you get 1.000 which converts to 1.

This will include some that aren't actually different, e.g., Number(".1") would produce 0.1 which is the correct conversion but it's explicitly mentioned to be incorrect.

Upvotes: 1

Ling Vu
Ling Vu

Reputation: 5181

Simply make a Regex check:

var reg = /^(0|-?[1-9]\d*\.?\d+)$/;

var value1 = '1e+30';
var value2 = ' 1';
var value3 = '.1';
var value4 = '01';

var value5 = '123';
var value6 = '1.2';
var value7 = '-1.2';

var reg = /^(0|-?[1-9]\d*\.?\d+)$/;

// This should be false
console.log(reg.test(value1))

// This should be false
console.log(reg.test(value2))

// This should be false
console.log(reg.test(value3))

// This should be false
console.log(reg.test(value4))

// This should be true
console.log(reg.test(value5))

// This should be true
console.log(reg.test(value6))

// This should be true
console.log(reg.test(value7))
  • -? for 0 or 1 '-' Character
  • \d+ for 1 or more numbers
  • \.? for 0 or 1 decimal seperator

For more information there is a good documentation here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp

Upvotes: 0

Addis
Addis

Reputation: 2530

Using regular expression and Number.MAX_SAFE_INTEGER

let num = '090071';
const regx = /(^0$)|(^[1-9][0-9.-]{1,}$)/;

console.log(regx.test(num) && Number(num) <= Number.MAX_SAFE_INTEGER)

Upvotes: 0

Related Questions