javascript把IP地址轉爲數值幾種方案,來挑戰一下效率吧

爲何要轉化IP地址:

點分十進制表示法只是爲了讓人好記憶,並不能用於電腦運算;java

數據庫中跟IP地址有的字段通常都會存成整數,這樣便於查詢,也能夠提升了查詢速度;git

javascript中轉換的幾種方案:

首先說一下IP地址的驗證,github

這裏就用正則表達式驗證的方式,表達式以下正則表達式

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 就是這個了 , 雖然這個正則表達式有點長,但用它能夠把驗證和分割一步到位,後面轉換的時候就省掉了分割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);
}

若是不要驗證的話就能夠換一個帥氣一點的寫法:markdown

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進制的課哦。oop

上面按位運算看起來沒什麼問題,
試了幾個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,謝謝!

相關文章
相關標籤/搜索