How to implement a parseInt

Posted by mnetsys on Tue, 24 Mar 2020 15:10:59 +0100

function(string, [radix]) {}
  • If string is not of string type, convert string to string type first
  • string ignores leading and trailing whitespace
  • Parse the characters in turn. If the characters are not the characters in the specified Radix (for example, 'f' in base 3 and base 10 in base 2), stop parsing (except when the first character is' + 'or' - '), and return the parsed integer
  • If it cannot be resolved to an integer, NaN is returned
  • The default value of radix is not 10. When radix is undefined, 0 or unspecified, do the following
    • If the string starts with '0x' or '0x', the cardinality is 16
    • If the string starts with '0', the cardinality is 8 or 10 (the specific implementation of each browser is different, and es5 specifies 10 at this time)
    • If a string starts with any other character, the cardinality is 10
  • The range of radix is 2-36

Regardless of radix

code implementation

const _parseInt = (str, radix) => {
  if (typeof str !== 'string') str = String(str)
  str = str.trim()
  const regex = /^(?<fuhao>[\+|\-]*)(?<num>\d+)/
  if (!regex.test(str)) return NaN
  const groups = str.match(regex).groups
  radix = 10
  const arr = groups.num.split('')
  const len = arr.length
  let result = 0
  for(let i = 0; i < len; i++) {
    const num = arr[i] * Math.pow(10, len - i - 1)
    if (isNaN(num)) break
    else result += num
  }
  return result * (groups.fuhao === '-' ? -1 : 1)
}

test case

const assert = require('assert')
assert.strictEqual(_parseInt(null), NaN)
assert.strictEqual(_parseInt('0e0'), 0)
assert.strictEqual(_parseInt('08'), 8)
assert.strictEqual(_parseInt(0.0000003), 3)
assert.strictEqual(_parseInt(0.00003), 0)
assert.strictEqual(_parseInt(-0.0000003), -3)
assert.strictEqual(_parseInt('6.022e23'), 6)
assert.strictEqual(_parseInt(6.022e2), 602)

Consider radix

code implementation

const _parseInt = (str, radix) => {
  // Do not convert to string type first for string type
  if (typeof str !== 'string') str = String(str)

  // Remove leading and trailing blanks
  str = str.trim()

  // Regular match [+ | -]? [0]?[Xx]?[0-9a-fA-F]+
  const regex = /^(?<fuhao>[\+|\-]*)(?<radix>[0]?[Xx]?)(?<num>[0-9a-fA-F]+)/

  // Cannot match return NaN
  if (!regex.test(str)) return NaN

  // Match the three groups of symbol, base and number
  const groups = str.match(regex).groups

  // The effective range of radix is 2-36
  if (radix && (radix < 2 || radix > 36)) return NaN

  // If radius is not specified, it will have the following default values
  if (!radix) {
    if (groups.radix.toUpperCase() === '0X') radix = 16
    else if (groups.radix === '0') radix = 8
    else radix = 10
  }

  // Parse string by string. If it fails to parse, stop parsing and return the parsed integer
  let splitArr = groups.num.split('')
  const arr = []
  for(let i = 0; i < splitArr.length; i++) {
    // According to the actual data of charCode, 0-9 is [48-57],A-F is [65-70]
    const charCode = splitArr[i].toUpperCase().charCodeAt()
    let num 

    // When the character is [A-F], the actual number is charCode -55
    if(charCode >= 65) num = charCode - 55

    // When the character is [0-9], the actual number is charCode - 48
    else num = charCode - 48

    // Stop string traversal when the actual number is greater than radius and cannot be parsed
    if (num > radix) {
      break
    } else {
      arr.push(num)
    }
  }

  const len = arr.length
  // When the actual number array length is 0, NaN is returned
  if(!len) return NaN
  let result = 0

  // Analyze the array of actual numbers in turn and combine them into real numbers
  for(let i = 0; i < len; i++) {
    const num = arr[i] * Math.pow(radix, len - i - 1)
    result += num
  }

  // Sign matching algorithm
  return result * (groups.fuhao === '-' ? -1 : 1)
}

test case

const assert = require('assert')

// Back to 15
assert.strictEqual(_parseInt('0xF', 16), 15)
assert.strictEqual(_parseInt('F', 16), 15)
assert.strictEqual(_parseInt('17', 8), 15)
assert.strictEqual(_parseInt(021, 8), 15)
assert.strictEqual(_parseInt('015', 10), 15)
assert.strictEqual(_parseInt(15.99, 10), 15)
assert.strictEqual(_parseInt('15,123', 10), 15)
assert.strictEqual(_parseInt('FXX123', 16), 15)
assert.strictEqual(_parseInt('1111', 2), 15)
assert.strictEqual(_parseInt('15 * 3', 10), 15)
assert.strictEqual(_parseInt('15e2', 10), 15)
assert.strictEqual(_parseInt('15px', 10), 15)
assert.strictEqual(_parseInt('12', 13), 15)

// Return to NaN below
assert.strictEqual(_parseInt('Hello', 8), NaN)
assert.strictEqual(_parseInt('546', 2), NaN)  

// Return below - 15
assert.strictEqual(_parseInt('-F', 16), -15)
assert.strictEqual(_parseInt('-0F', 16), -15)
assert.strictEqual(_parseInt('-0XF', 16), -15)
assert.strictEqual(_parseInt(-15.1, 10), -15)
assert.strictEqual(_parseInt(' -17', 8), -15)
assert.strictEqual(_parseInt(' -15', 10), -15)
assert.strictEqual(_parseInt('-1111', 2), -15)
assert.strictEqual(_parseInt('-15e1', 10), -15)
assert.strictEqual(_parseInt('-12', 13), -15)

// Return to 4 below
assert.strictEqual(_parseInt(4.7, 10), 4)
assert.strictEqual(_parseInt(4.7 * 1e22, 10), 4)
assert.strictEqual(_parseInt(0.00000000000434, 10), 4)

// Return to 224 below
assert.strictEqual(_parseInt('0e0', 16), 224)

Topics: Javascript