// 识别有效的IP地址和掩码并进行分类统计
// https://www.nowcoder.com/practice/de538edd6f7e4bc3a5689723a7435682
#include <iostream>
#include <string>
#include <algorithm>
#include <bitset>
#include <vector>
#include <sstream>
using namespace std;
enum IPAddressType {
ERROR_IP = -1,
A_IP,
B_IP,
C_IP,
D_IP,
E_IP,
OTHERS_IP
};
struct IPAndMaskResult {
IPAddressType ipType {ERROR_IP};
bool isPrivateIP {};
bool isValidMask {};
};
struct IPAndMaskValidNum {
int A_IP_Num {};
int B_IP_Num {};
int C_IP_Num {};
int D_IP_Num {};
int E_IP_Num {};
int ERR_IP_Num {};
int ERR_Mask_Num {};
int Private_IP_Num {};
};
// 子网掩码要求为3点分制格式
bool IsValidMask(const string mask)
{
stringstream ss(mask);
string tmp {};
string bitStr {};
bool isValidMask = true;
while (getline(ss, tmp, '.')) {
bitset<8> b((int)stoi(tmp));
bitStr += b.to_string();
}
auto iter = bitStr.find('1');
if (iter != bitStr.npos) {
bitStr = bitStr.substr(iter);
}
if (bitStr.find("10") == bitStr.npos ||
bitStr.find("01") != bitStr.npos ) {
isValidMask = false;
}
// cout <<"inMask:" << mask <<" bitStr:" <<bitStr <<" isValid:" <<isValidMask <<endl;
return isValidMask;
}
IPAndMaskResult CheckIPAddrType(const string IP)
{
IPAndMaskResult ipAndMaskRes {};
const int ipLen = 4;
stringstream ss(IP);
string tmp {};
int ipNum[ipLen] {};
int index = 0;
while (getline(ss, tmp, '.')) {
if (tmp.size() == 0 || stoi(tmp) > 255) {
ipAndMaskRes.ipType = ERROR_IP;
return ipAndMaskRes; // valid ip quit directly
}
ipNum[index++] = stoi(tmp);
}
if (ipNum[0] == 0 || ipNum[0] == 127) {
ipAndMaskRes.ipType = OTHERS_IP;
return ipAndMaskRes;
}
if ((ipNum[0] == 10) ||
(ipNum[0] == 172 && ipNum[1] >= 16 && ipNum[1] <= 31) ||
(ipNum[0] == 192 && ipNum[1] == 168)) {
ipAndMaskRes.isPrivateIP = true;
}
if (ipNum[0] >= 1 && ipNum[0] <= 126) {
ipAndMaskRes.ipType = A_IP;
} else if (ipNum[0] >= 128 && ipNum[0] <= 191) {
ipAndMaskRes.ipType = B_IP;
} else if (ipNum[0] >= 192 && ipNum[0] <= 223) {
ipAndMaskRes.ipType = C_IP;
} else if (ipNum[0] >= 224 && ipNum[0] <= 239) {
ipAndMaskRes.ipType = D_IP;
} else if (ipNum[0] >= 240 && ipNum[0] <= 255) {
ipAndMaskRes.ipType = E_IP;
} else {
ipAndMaskRes.ipType = ERROR_IP;
}
return ipAndMaskRes;
}
IPAndMaskResult Solution(const string IPAndMask)
{
IPAndMaskResult ipAndMaskRes {};
string ip {};
string mask {};
string tmp = IPAndMask;
auto iter = IPAndMask.find('~');
if (iter != IPAndMask.npos) {
ip = IPAndMask.substr(0, iter);
if (iter+1 < IPAndMask.size()) {
mask = IPAndMask.substr(iter+1);
}
}
ipAndMaskRes = CheckIPAddrType(ip);
ipAndMaskRes.isValidMask = IsValidMask(mask);
return ipAndMaskRes;
}
int main()
{
IPAndMaskValidNum ipAndMaskValidNum {};
IPAndMaskResult ipAndMaskRes {};
string IPAndMask {};
while (getline(cin, IPAndMask)) {
ipAndMaskRes = Solution(IPAndMask);
if (ipAndMaskRes.ipType == OTHERS_IP) {
continue;
}
if (!ipAndMaskRes.isValidMask) {
ipAndMaskValidNum.ERR_Mask_Num ++;
continue;
}
switch (ipAndMaskRes.ipType) {
case ERROR_IP: ipAndMaskValidNum.ERR_IP_Num ++; break;
case A_IP: ipAndMaskValidNum.A_IP_Num ++; break;
case B_IP: ipAndMaskValidNum.B_IP_Num ++; break;
case C_IP: ipAndMaskValidNum.C_IP_Num ++; break;
case D_IP: ipAndMaskValidNum.D_IP_Num ++; break;
case E_IP: ipAndMaskValidNum.E_IP_Num ++; break;
default:
break;
}
if (ipAndMaskRes.isPrivateIP) {
ipAndMaskValidNum.Private_IP_Num ++;
}
}
cout << ipAndMaskValidNum.A_IP_Num << " "
<< ipAndMaskValidNum.B_IP_Num << " "
<< ipAndMaskValidNum.C_IP_Num << " "
<< ipAndMaskValidNum.D_IP_Num << " "
<< ipAndMaskValidNum.E_IP_Num << " "
<< ipAndMaskValidNum.ERR_IP_Num + ipAndMaskValidNum.ERR_Mask_Num << " "
<< ipAndMaskValidNum.Private_IP_Num <<endl;
return 0;
}