描述
编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址
IPv4 地址由十进制数和点来表示,每个地址包含4个十进制数,其范围为 0 - 255, 用(“.”)分割。比如,172.16.254.1;
同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。
IPv6 地址由8组16进制的数字来表示,每组表示 16 比特。这些组数字通过 (“:”)分割。比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。
然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 ( ::) 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。
同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。
说明: 你可以认为给定的字符串里没有空格或者其他特殊字符。
示例1
输入:“172.16.254.1”
返回值:“IPv4”
示例2
输入:“2001:0db8:85a3:0:0:8A2E:0370:7334”
返回值:“IPv6”
示例3
输入:“256.256.256.256”
返回值:“Neither”
思路:分别写一个判断IPv4的函数和IPv6函数,最后在总的判断函数中调用。
判断IPv4的条件:
将每一段放进数组,是一个字符串数组
(1)是否是4段(即判断数组长度是否为4)
(2)每一段中是否有空 NaN
(3)每一段中数字是否在0-255之间(字符串转化为Int判断)
(4)每一段中是否有0开头的(即判断字符串首位是否为0,单独的0是可以,即再加一个条件,判断字符串长度是否不等于1)
判断IPv6的条件:
将每一段放进数组,是一个字符串数组
(1)是否是8段(即判断数组长度是否为8)
(2)每一段中是否有空 NaN
(3)每一段的字符串成都是否大于4(大于4即不是IPv6)
/**
* 验证IP地址
* @param IP string字符串 一个IP地址字符串
* @return string字符串
*/
function solve( IP ) {
return checkIPv4(IP)?"IPv4":(checkIPv6(IP)?"IPv6":"Neither");
}
function checkIPv4(IP){
let arr=IP.split(".");
if(arr.length!==4) return false;
for(let i of arr){
if(Object.is(Number(i),NaN)||Number(i)>255||Number(i)<0||i[0]==='0'&&i.length!==1){
return false;
}
}
return true;
}
function checkIPv6(IP){
let arr=IP.split(":");
if(arr.length!==8) return false;
for (let i of arr){
if(i.length>4||Object.is(parseInt(i,16),NaN)){
return false;
}
}
return true;
}
module.exports = {
solve : solve
};
总结:本题所用的知识点
1. String对象中的方法 split()
split() 方法用于把一个字符串分割成字符串数组。
stringObject.split(separator,howmany)
参数说明
(1)separator:必需。字符串或正则表达式,从该参数指定的地方分割 stringObject。
(2)如果把空字符串 (“”) 用作 separator,那么 stringObject 中的每个字符之间都会被分割。
(3)howmany:可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。
2. 数组长度以及字符串的长度
arr.length
s.length
3. for…of循环
for (variable of iterable) {
//statements
}
参数说明:
variable:在每次迭代中,将不同属性的值分配给变量。
iterable:被迭代枚举其属性的对象。
举例:
//迭代Array
let iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value);
}
// 10
// 20
// 30
//迭代String
let iterable = "boo";
for (let value of iterable) {
console.log(value);
}
// "b"
// "o"
// "o"
for…of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
for…in和for…of的区别及用法
无论是for…in还是for…of语句都是迭代一些东西。它们之间的主要区别在于它们的迭代方式。
for…in 语句以任意顺序迭代对象的可枚举属性。
for…of 语句遍历可迭代对象定义要迭代的数据。
MDN 实例:
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
iterable.foo = 'hello';
console.log(iterable);
for (let i in iterable) {
console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // logs 0, 1, 2, "foo"
}
}
for (let i of iterable) {
console.log(i); // logs 3, 5, 7
}
参考原文
以上三个结果中:
(1)console.log(iterable) 返回数组本身
(2)第一个for…in结果看出,可枚举属性除了本身的 0 , 1 , 2 ,foo之外,还有 arrCustom, objCustom。这是由于继承功能, iterable是数组实例,iterable.__proto__指向Array原型对象则有了前面定义的属性arrCustom, 而Array.__proto__指向Object原型对象,则有了前面定义的熟悉objCustom, 原型链在往上Object.__proto__指向null,此时终止继承。
(3)第二个for…in内部使用hasOwnProperty判断只有是本身的属性才输出
而for…of该循环迭代并记录iterable作为可迭代对象定义的迭代值,这些是数组元素 3, 5, 7,而不是任何对象的属性。
4. JavaScript内置对象Object中方法Object.is()
Object.is() 方法判断两个值是否为同一个值。
Object.is(value1, value2);
参数说明:
value1:被比较的第一个值。
value2:被比较的第二个值。
返回值:一个 Boolean 类型标示两个参数是否是同一个值。
描述:Object.is() 方法判断两个值是否为同一个值。如果满足以下条件则两个值相等:
都是 undefined;都是 null;都是 true 或 false;都是相同长度的字符串且相同字符按相同顺序排列;都是相同对象(意味着每个对象有同一个引用)
都是数字且都是 +0;都是 -0;都是 NaN;或都是非零而且非 NaN 且为同一个值
与== 运算不同。 == 运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换 (这种行为的结果会将 “” == false 判断为 true), 而 Object.is不会强制转换两边的值。
与=== 运算也不相同。 === 运算符 (也包括 == 运算符) 将数字 -0 和 +0 视为相等 ,而将Number.NaN 与NaN视为不相等.
// 特例
Object.is(0, -0); // false
Object.is(0, +0); // true
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true
5. JavaScript全局对象中的parseInt() 函数
parseInt() 函数可解析一个字符串,并返回一个整数。
parseInt(string, radix)
参数说明:
string:必需。要被解析的字符串。
radix:可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。
返回值:返回解析后的数字。
说明:当参数 radix 的值为 0,或没有设置该参数时,parseInt() 会根据 string 来判断数字的基数。举例,如果 string 以 “0x” 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。如果 string 以 0 开头,那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析为八进制或十六进制的数字。如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。
parseInt("10"); //返回 10
parseInt("19",10); //返回 19 (10+9)
parseInt("11",2); //返回 3 (2+1)
parseInt("17",8); //返回 15 (8+7)
parseInt("1f",16); //返回 31 (16+15)
parseInt("010"); //未定:返回 10 或 8