sisterAn / JavaScript-Algorithms

基础理论+JS框架应用+实践,从0到1构建整个前端算法体系
5.51k stars 634 forks source link

百度:手写parseInt的实现,要求简单一些,把字符串型的数字转化为真正的数字即可,但不能使用JS原生的字符串转数字的API,比如Number() #89

Open sisterAn opened 4 years ago

sisterAn commented 4 years ago

返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN

注意:radix 参数为 n 将会把第一个参数看作是一个数的 n 进制表示,而返回的值则是十进制的。例如:

parseInt('123', 5) // 将'123'看作5进制数,返回十进制数38 => 3*5^0 + 2*5^1 + 1*5^2  = 38

以下 2 进制没有问题

function _parseInt(str, radix) {
    let str_type = typeof str;
    let res = 0;
    if (str_type !== 'string' && str_type !== 'number') {
        // 如果类型不是 string 或 number 类型返回NaN
        return NaN
    }

    // 字符串处理
    str = String(str).trim().split('.')[0]
    let length = str.length;
    if (!length) {
        // 如果为空则返回 NaN
        return NaN
    }

    if (!radix) {
        // 如果 radix 为0 null undefined
        // 则转化为 10
        radix = 10;
    }
    if (typeof radix !== 'number' || radix < 2 || radix > 36) {
        return NaN
    }

    for (let i = 0; i < length; i++) {
        let arr = str.split('').reverse().join('');
        res += Math.floor(arr[i]) * Math.pow(radix, i)
    }

    return res;
}

考虑 16 进制,完整版如下

const _parseInt = (str, radix) => {
  // 不为string类型先转化为string 类型
  if (typeof str !== 'string') str = String(str)

  // 删除首尾空白
  str = str.trim()

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

  // 无法匹配返回NaN
  if (!regex.test(str)) return NaN

  // 匹配出符号、进制、数字三个分组
  const groups = str.match(regex).groups

  // radix的有效范围为 2-36
  if (radix && (radix < 2 || radix > 36)) return NaN

  // 如果没有指定radix, radix 会有以下默认值
  if (!radix) {
    if (groups.radix.toUpperCase() === '0X') radix = 16
    else if (groups.radix === '0') radix = 8
    else radix = 10
  }

  // 挨个字符串解析,如果遇到无法解析时则停止解析,返回已经解析好的整数
  let splitArr = groups.num.split('')
  const arr = []
  for(let i = 0; i < splitArr.length; i++) {
    // 根据charCode来做转行为实际数据, 0-9为[48-57],A-F为[65-70]
    const charCode = splitArr[i].toUpperCase().charCodeAt()
    let num 

    // 字符为[A-F]时, 实际数字为charCode -55
    if(charCode >= 65) num = charCode - 55

    // 字符为[0-9]时, 实际数字为charCode - 48
    else num = charCode - 48

    // 当实际数字大于radix时, 无法解析则停止字符串遍历
    if (num > radix) {
      break
    } else {
      arr.push(num)
    }
  }

  const len = arr.length
  // 当实际数字数组长度为0时, 返回NaN
  if(!len) return NaN
  let result = 0

  // 依次解析实际数字数组, 组合成真正的数字
  for(let i = 0; i < len; i++) {
    const num = arr[i] * Math.pow(radix, len - i - 1)
    result += num
  }

  // 算法匹配到的正负号
  return result * (groups.fuhao === '-' ? -1 : 1)
}
dlrandy commented 3 years ago

const regex = /^(?[+|-]*)(?[0]?[Xx]?)(?[0-9a-fA-F]+)/ 这里是什么原因不用问号? const regex = /^(?[+|-]?)(?[0]?[Xx]?)(?[0-9a-fA-F]+)/

xllpiupiu commented 3 years ago
//可以传两个参数  parsenInt('123',5)将'123'看作5进制 返回10进制
function _parseInt2(str, radix) {
    //1. 对入参做判断
    let strType = typeof str
    if (strType !== 'string' && strType !== 'number') return NaN
    if (typeof radix !== 'number' || radix < 2 || radix > 36) return NaN
    //2. 对str做处理 只取整数部分
    let strHandle = String(str).trim().split('.')[0]
    console.log('strHandle: ', strHandle);
    if (strHandle.length === 0) return NaN
    //3. radix处理
    if (!radix) radix = 10
    //4. 转换逻辑  将字符反转
    let strReverse = strHandle.split('').reverse().join('')
    console.log('strReverse: ', strReverse);
    let res = 0
    for (let i = 0, len = strReverse.length; i < len; i++) {
        if (strReverse[i] >= radix) return NaN
        res += strReverse[i] * Math.pow(radix, i)
    }
    return res
}
console.log(_parseInt2('123', 5))