-
Notifications
You must be signed in to change notification settings - Fork 57
IP地址转化为数值的方案
cnwhy edited this page Sep 18, 2013
·
2 revisions
首先是IP地址的验证,我选择了用正则表达式:
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就是这个了,虽然这个正则有点长,但用它可以把验证和分割一步到位,很方便;
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);
}
如果不要验证的话就可以换一个帅气一点的写法:
return parseInt(IP.replace(/\d+\.?/ig,function(a){
a = parseInt(a);
return (a > 15 ? "" : "0") + a.toString(16);
}),16);
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]));
}
我一想,直接记算还不如安位算于是改了一下:
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]));
}
上面按位运算看起来没什么问题,试了几个IP地址之后就发现不对了
当IP的值大于0x7f000000时变负数了,我了个去JS把它当成32位的整型,最左边一位成了符号位
本打算放弃的时候一想,不对啊,符号位不也就是0,1吗,JS还有无符号右移运算符呢(>>>)
于是上面的函数改良之后就成了这样:
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了。
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?
虽然"方案2"的代码更容易理解,但最后抱着对算法的敬畏还是选择了"方案3";