文章目錄
先看看什麼是IP地址:
IP地址是一個32位的位元,通常被分割為4個“8位位元”(也就是4個位元組)。IP地址通常用“點分十進位”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之間的十進位整數。例:點分十進IP地址(100.4.5.6),實際上是32位位元(01100100.00000100.00000101.00000110)。
為什麼要轉化IP地址:
點分十進位標記法只是為了讓人好記憶,並不能用於電腦運算;
資料庫中跟IP地址有的欄位一般都會存成整數,這樣便於查詢,也可以提高了查詢速度;
javascript中轉換的幾種方案:
首先說一下IP地址的驗證,
這裡就用Regex驗證的方式,運算式如下
var REG =/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
後面代碼中用到 REG 就是這個了 , 雖然這個Regex有點長,但用它可以把驗證和分割一步到位,後面轉換的時候就省掉了分割IP地址的步驟;
方案1:每8位轉成16進位字元,拼接後轉成整數
當IP地址通過用“.”分割後,每一段都因該是8位,所以我們剛好可以轉成兩位的16進位數,然後拼接16進位的字串,再轉為數字就OK了。
function ipToInt(IP){ var xH = "",result = REG.exec(ip); if(!result) return -1; for (var i = 1; i <= 4; i++) { var h = parseInt(result[i]); xH += (h > 15 ? "" : "0") + h.toString(16); } return parseInt(xH, 16);}
如果不要驗證的話就可以換一個帥氣一點的寫法:
function ipToInt(IP){ return parseInt(IP.replace(/\d+\.?/ig,function(a){ a = parseInt(a); return (a > 15 ? "" : "0") + a.toString(16); }),16);}
方案2:直接計算
知道了IP地址的結構,不難想到只要給分割之後的數字乘以相應的數,再加起來就OK了;
function ipToInt(IP){ var xH = "",result = REG.exec(ip); if(!result) return -1; return (parseInt(result[1]) * 0x1000000 + parseInt(result[2]) * 0x10000 + parseInt(result[3]) * 0x100 + parseInt(result[4]));}
方案3:按位計算
直接記算還不如按位元運算,那不是更快?
function ipToInt(IP){ var xH = "",result = REG.exec(ip); if(!result) return -1; return (parseInt(result[1]) << 24 | parseInt(result[2]) << 16 | parseInt(result[3]) << 8 | parseInt(result[4]));}
如果看不明白,還請回去補一下2進位的課哦。
上面按位元運算看起來沒什麼問題,
試了幾個IP地址之後就發現不對了, 最後發現 當IP的值大於0x7fffffff(127.255.255.255)時變負數了也就是。
原因是JS按位元運算的時候都是當成32位的整型來算的,本來剛好32位,結果最左邊一位成了符號位,不夠用了
是不是很多同學在發現溢出之後就放棄這個安案了呐。
我來本打算放棄的時候一想,不對啊,符號位不也就是0,1嗎,不是還有">>>"無符號右移運算子嗎,我無符號右移0位行不行呐:
function ipToInt(IP){ var xH = "",result = REG.exec(ip); if(!result) return -1; return (parseInt(result[1]) << 24 | parseInt(result[2]) << 16 | parseInt(result[3]) << 8 | parseInt(result[4]))>>>0;}
測試之後果然OK,萬幸IP地址是32位,剛剛好,不然這個方案只能放棄了。
方案4:按位,字串拼接結合(純屬於瞎折騰)
function ipToInt(IP) { var xH = "", result = REG.exec(ip); if (!result) return - 1; var ip2 = "000000" + ((parseInt(result[2]) << 16) | (parseInt(result[3]) << 8) | parseInt(result[4])).toString(16); return parseInt(parseInt(result[1]).toString(16) + ip2.substr(ip2.length - 6), 16);}
你肯定在問為什麼會有這麼怪的想法,其實是安位元運算出現了符號位的問題不甘心放棄,這個想法就這麼出來了.
總結
照道理說"方案3"因該是最有效率的方法.
但最後100萬次的運算測試表明"方案2"的效率和"方案3"相差無幾,難道是因為V8?
附上一個反函數:
function intToIp(INT){ if(INT < 0 || INT > 0xFFFFFFFF){ throw ("The number is not normal!"); } return (INT>>>24) + "." + (INT>>16 & 0xFF) + "." + (INT>>8 & 0xFF) + "." + (INT & 0xFF);}
轉載請註明出處 http://www.cnblogs.com/whyoop,謝謝!