如何實現一個parseInt 如果string不為字元串類型, 則先將string轉化為字元串類型 string會忽略前後的空白 依次解析字元, 如果字元不是指定基數中的字元( 例如:2進位中的3、 10進位中的'f' )則停止解析( 首字元為'+'或' '時除外 ), 返回已經解析好的整數 如果無 ...
如何實現一個parseInt
function(string, [radix]) {}
- 如果string不為字元串類型, 則先將string轉化為字元串類型
- string會忽略前後的空白
- 依次解析字元, 如果字元不是指定基數中的字元( 例如:2進位中的3、 10進位中的'f' )則停止解析( 首字元為'+'或'-'時除外 ), 返回已經解析好的整數
- 如果無法解析為整數, 則返回NaN
- radix 預設值不為10, 在radix為undefined、0或者沒有指定時, 做以下處理
- 如果string以'0X'或'0x'開頭時, 基數為16
- 如果string以'0'開頭時, 基數為8或者10(每個瀏覽器的具體實現不同, es5規定此時為10)
- 如果string以其他任何字元開頭時, 基數為10
- radix的範圍為2-36
不考慮進位radix
代碼實現
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)
}
測試用例
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)
考慮radix
代碼實現
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)
}
測試用例
const assert = require('assert')
// 以下返回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)
// 以下返回NaN
assert.strictEqual(_parseInt('Hello', 8), NaN)
assert.strictEqual(_parseInt('546', 2), NaN)
// 以下返回-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)
// 以下返回4
assert.strictEqual(_parseInt(4.7, 10), 4)
assert.strictEqual(_parseInt(4.7 * 1e22, 10), 4)
assert.strictEqual(_parseInt(0.00000000000434, 10), 4)
// 以下返回224
assert.strictEqual(_parseInt('0e0', 16), 224)