题目背景
我们需要处理一种特殊的虚拟IPv4地址,这种地址由4个小节组成,每节之间用#
分隔。与标准IPv4地址不同,虚拟IPv4地址的第一节范围是1~128
,后三节的范围是0~255
。我们需要将这种虚拟IPv4地址转换为一个唯一的32位整数。如果输入的地址不合法,则返回invalid IP
。
输入输出
- 输入:一行字符串,表示虚拟IPv4地址,例如
128#0#255#255
或1#0#0#0
。 - 输出:
- 如果地址合法,输出对应的32位整数(十进制形式),例如
2147549183
或16777216
。 - 如果地址非法,输出
invalid IP
。
- 如果地址合法,输出对应的32位整数(十进制形式),例如
地址合法性规则
- 格式:必须由4个小节组成,以
#
分隔,例如A#B#C#D
。 - 范围:
- 第一节(A):
1~128
(闭区间)。 - 第二节(B)、第三节(C)、第四节(D):
0~255
(闭区间)。
- 第一节(A):
- 其他非法情况:
- 小节数量不是4个。
- 某一个小节不是数字。
- 数字超出范围。
- 数字前导有无效字符(例如
012
是合法的,但+12
或12a
是非法的)。
转换规则
将虚拟IPv4地址的4个小节分别看作一个8位二进制数,按顺序拼接成一个32位二进制数,然后转换为十进制整数。具体步骤如下:
- 将每一节转换为8位二进制:
- 第一节(A):
A
的二进制,高位补0到8位。 - 第二节(B):
B
的二进制,高位补0到8位。 - 第三节(C):
C
的二进制,高位补0到8位。 - 第四节(D):
D
的二进制,高位补0到8位。
- 第一节(A):
- 拼接4个8位二进制,得到一个32位二进制数。
- 将32位二进制数转换为十进制整数。
示例
-
输入:
128#0#255#255
- 解析:
- 第一节:128 →
10000000
- 第二节:0 →
00000000
- 第三节:255 →
11111111
- 第四节:255 →
11111111
- 第一节:128 →
- 拼接:
10000000 00000000 11111111 11111111
→0x8000FFFF
- 十进制:2147549183
- 输出:
2147549183
- 解析:
-
输入:
1#0#0#0
- 解析:
- 第一节:1 →
00000001
- 第二节:0 →
00000000
- 第三节:0 →
00000000
- 第四节:0 →
00000000
- 第一节:1 →
- 拼接:
00000001 00000000 00000000 00000000
→0x01000000
- 十进制:16777216
- 输出:
16777216
- 解析:
-
输入:
129#0#0#0
- 解析:第一节是129,超出
1~128
范围。 - 输出:
invalid IP
- 解析:第一节是129,超出
-
输入:
128#0#255
- 解析:只有3个小节,不合法。
- 输出:
invalid IP
解题思路
- 输入校验:
- 检查是否由4个小节组成(用
#
分隔)。 - 检查每一小节是否为纯数字(无前导符号或字母)。
- 检查数字范围:
- 第一节:
1~128
。 - 后三节:
0~255
。
- 第一节:
- 检查是否由4个小节组成(用
- 转换:
- 将每一节转换为整数。
- 将每一节转换为8位二进制字符串。
- 拼接4个8位二进制字符串。
- 将32位二进制字符串转换为十进制整数。
- 输出:
- 合法:输出整数。
- 非法:输出
invalid IP
。
const readline = require('readline');
// 判断字符串是否为数字
function isNumeric(str) {
for (let i = 0; i < str.length; i++) {
if (!/\d/.test(str[i])) {
return false; // 如果有非数字字符则返回false
}
}
return true; // 全部为数字则返回true
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', function (input) {
const ipSections = input.split('#'); // 将输入的字符串按照"#"分割成4个小节
if (ipSections.length !== 4) { // 如果分割后的小节数量不等于4,则说明输入的IPv4地址格式不正确
console.log("invalid IP");
rl.close();
return;
}
// 遍历每个部分进行检查
for (const section of ipSections) {
if (section.length === 0 || !isNumeric(section)) { // 检查是否为空或者是否每部分都是数字
console.log("invalid IP");
rl.close();
return;
}
// 检查前导零的情况
if (section.length > 1 && section[0] === '0') {
console.log("invalid IP");
rl.close();
return;
}
}
const firstSection = parseInt(ipSections[0], 10); // 将第一个小节转换为整数
if (firstSection < 1 || firstSection > 128) { // 如果第一个小节的值不在1~128的范围内
console.log("invalid IP");
rl.close();
return;
}
// 检查其余3个小节的范围
for (let i = 1; i < 4; i++) {
const sectionValue = parseInt(ipSections[i], 10); // 将当前小节转换为整数
if (sectionValue < 0 || sectionValue > 255) { // 如果不在0~255范围内
console.log("invalid IP");
rl.close();
return;
}
}
// 计算最终的32位整数
let ipValue = 0;
//左移8位和并累加,在二进制中,乘以256(即 2^8)相当于将数字向左移动8位,空出最低的8位用于存放下一个字节
for (let i = 0; i < 4; i++) {
ipValue = ipValue * 256 + parseInt(ipSections[i], 10); // 每个小节对应一个字节,计算最终的整数值
}
console.log(ipValue); // 输出最终的32位整数
rl.close();
});