描述
在本题中,我们需要处理地址信息,其由 IP 地址和子网掩码组成,这两者均形如 "*.*.*.*",由四段数字组成(每一个 '*'表示一个数字),每一段的数字均为 00到 255 之间的一个整数,每段数字之间以点分隔。
我们定义五类 IP 地址:
∙ ∙A 类:"1.0.0.0"∼"127.255.255.255";
∙ ∙B 类:"128.0.0.0"∼"191.255.255.255";
∙ ∙C 类:"192.0.0.0"∼"223.255.255.255";
∙ ∙D 类:"224.0.0.0"∼"239.255.255.255";
∙ ∙E 类:"240.0.0.0"∼"255.255.255.255"。
我们定义私有 IP 地址:
∙ ∙"10.0.0.0"∼"10.255.255.255";
∙ ∙"172.16.0.0"∼"172.31.255.255";
∙ ∙"192.168.0.0"∼"192.168.255.255"。
我们定义合法的子网掩码为:将掩码的每一段数字依次转换为八位长度的二进制字符串并进行拼接,这个字符串必须由若干个连续的 1 后跟若干个连续的 0 组成,才视为子网掩码合法。例如,掩码 "255.254.255.0"转换拼接得到字符串 11111111 11111110 11111111 00000000,显然不合法;掩码 "255.255.255.248" 转换拼接得到字符串 11111111 11111111 11111111 11111000,合法。注意,全为 1 或全为 0 的掩码也视为非法。
我们定义错误的 IP 地址和错误的子网掩码为不符合上述定义的 IP 地址和子网掩码。例如,格式错误、数字超出范围等等。
现在,你需要分类统计 A、B、C、D、E 类地址的数量、错误 IP 或错误子网掩码的数量、私有 IP 的数量。
特别地:
- ∙ ∙类似 "0.*.*.*"和 "127.*.*.*"的 IP 地址不计入任何类别,也不计入非法统计,直接跳过;
- ∙ ∙一个 IP 既可计入私有 IP,也可计入五类地址之一,二者分别累计。
输入描述:
本题将会给出 1≦T≦1000 条地址信息,确切数字未知,您需要一直读取至文件结尾;每条地址信息描述如下:
每行输入一个 "*.*.*.*"形式的 IP 地址和一个 "*.*.*.*"形式的子网掩码,中间用波浪线(∼)分隔。保证 '*'要么为空,要么是一个 0 到 255 间的整数。
输出描述:
在一行上输出七个整数,分别代表 A 类地址数、B 类地址数、C 类地址数、D 类地址数、E 类地址数、错误 IP 或错误子网掩码数、私有 IP 数。
示例1
输入:
10.70.44.68~1.1.1.5
1.0.0.1~255.0.0.0
192.168.0.2~255.255.255.0
19..0.~255.255.255.0
输出:
1 0 1 0 0 2 1
说明:
在这个样例中:
∙第一条地址信息:掩码非法;
∙第二条地址信息:IP 格式和掩码均合法,属于 A 类;
∙第三条地址信息:IP 格式和掩码均合法,属于 C 类私有地址;
∙第四条地址信息:IP 格式非法。
统计得到 1 个 A 类,0 个 B 类,1 个 C 类,0 个 D 类,0 个 E 类,2 个错误条目,1 个私有地址。
示例2
输入:
0.201.56.50~255.255.255.0
127.201.56.50~255.255.111.255
输出:
0 0 0 0 0 0 0
说明:
在这个样例中,两条地址信息均属于上方提示中提到的特殊 IP 地址,不需要处理,直接跳过。特别需要注意地,第二条地址的子网掩码是非法的。但是因为该条为特殊 IP 地址,此优先级更高,所以不进入统计。
解题思路
步骤分解:
-
读取输入:逐行读取,直到EOF
-
解析每行:分割IP和掩码
-
验证IP:检查格式和有效性
-
验证掩码:检查是否为合法子网掩码
-
特殊IP检查 :如果是0.. .或127. .*.*则跳过
-
分类统计:
-
按类别统计A/B/C/D/E
-
检查是否为私有IP
-
错误统计
-
-
输出结果:7个统计数字
JavaScript 解决方案
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 统计结果
let A = 0, B = 0, C = 0, D = 0, E = 0;
let error = 0;
let privateIP = 0;
// 验证IP地址格式
function isValidIP(ip) {
if (!ip) return false;
const parts = ip.split('.');
if (parts.length !== 4) return false;
for (let part of parts) {
if (part === '' || isNaN(part)) return false;
const num = parseInt(part, 10);
if (num < 0 || num > 255) return false;
// 检查是否有非法前导零(除非数字本身就是0)
if (num.toString() !== part) {
return false;
}
}
return true;
}
// 验证子网掩码
function isValidMask(mask) {
if (!isValidIP(mask)) return false;
const parts = mask.split('.');
let binaryStr = '';
// 转换为32位二进制字符串
for (let part of parts) {
const num = parseInt(part, 10);
binaryStr += num.toString(2).padStart(8, '0');
}
// 查找第一个0的位置
const firstZeroIndex = binaryStr.indexOf('0');
// 查找最后一个1的位置
const lastOneIndex = binaryStr.lastIndexOf('1');
// 检查掩码是否全0或全1
if (firstZeroIndex === -1 || lastOneIndex === -1) {
return false; // 全1或全0都不合法
}
// 检查是否连续的1后接连续的0
// 如果有1在0后面,则不合法
if (lastOneIndex > firstZeroIndex) {
return false;
}
return true;
}
// 判断是否为特殊IP(0.*.*.* 或 127.*.*.*)
function isSpecialIP(ipParts) {
const first = parseInt(ipParts[0], 10);
return first === 0 || first === 127;
}
// 判断是否为私有IP
function isPrivateIP(ipParts) {
const first = parseInt(ipParts[0], 10);
const second = parseInt(ipParts[1], 10);
// 10.0.0.0 - 10.255.255.255
if (first === 10) return true;
// 172.16.0.0 - 172.31.255.255
if (first === 172 && second >= 16 && second <= 31) return true;
// 192.168.0.0 - 192.168.255.255
if (first === 192 && second === 168) return true;
return false;
}
// 获取IP类别
function getIPClass(ipParts) {
const first = parseInt(ipParts[0], 10);
if (first >= 1 && first <= 126) return 'A';
if (first >= 128 && first <= 191) return 'B';
if (first >= 192 && first <= 223) return 'C';
if (first >= 224 && first <= 239) return 'D';
if (first >= 240 && first <= 255) return 'E';
return null;
}
// 处理一行输入
function processLine(line) {
line = line.trim();
if (!line) return;
const parts = line.split('~');
if (parts.length !== 2) {
error++;
return;
}
const [ipStr, maskStr] = parts;
// 首先验证IP格式
if (!isValidIP(ipStr)) {
error++;
return;
}
const ipParts = ipStr.split('.');
// 如果是特殊IP(0.*.*.* 或 127.*.*.*),直接跳过
if (isSpecialIP(ipParts)) {
return; // 注意:这里直接返回,不检查掩码,也不计入错误
}
// 验证掩码
if (!isValidMask(maskStr)) {
error++;
return; // 掩码非法,计入错误并返回
}
// 统计私有IP
if (isPrivateIP(ipParts)) {
privateIP++;
}
// 统计IP类别
const ipClass = getIPClass(ipParts);
switch (ipClass) {
case 'A': A++; break;
case 'B': B++; break;
case 'C': C++; break;
case 'D': D++; break;
case 'E': E++; break;
}
}
// 读取输入
rl.on('line', (line) => {
processLine(line);
});
// 输出结果
rl.on('close', () => {
console.log(`${A} ${B} ${C} ${D} ${E} ${error} ${privateIP}`);
});