IP报文头解析问题 | 豆包MarsCode AI刷题

192 阅读3分钟

问题描述

小R 负责解析IP报文头信息,现有一个十六进制格式的IP报文头数据 header,他需要从中解析并输出其中的总长度、标志位以及目的IP地址,用逗号分隔。
IP报文头信息依次包含多个字段,其中标识(16位)和目的IP地址(32位)是重点。输入数据为合法的十六进制IP报文头,固定长度为59个字符,每两个十六进制数字表示一个字节,字节之间以单空格分隔。

注:报文数据为大端序(即高位字节在低地址),小R需要将这些数据进行解析,输出的总长度和标志为十进制整数,目的IP地址为点分十进制格式(如192.168.20.184)。

IP报文头

返回规则如下:

  • 解析其中的总长度、标志位以及目的IP地址,用逗号分隔。

示例 1:

输入:header = "45 00 10 3c 7c 48 20 03 80 06 00 00 c0 a8 01 02 c0 a8 14 b8"
输出:"4156,1,192.168.20.184"

示例 2:

输入:header = "4b ba 0d 15 d0 42 16 bc 50 25 38 33 cb e0 77 ed 56 a4 30 46"
输出:"3349,0,86.164.48.70"

示例 3:

输入:header = "f7 87 78 be cf bf ae 9e d6 bc b1 5f 38 2c 07 37 95 f8 32 c5"
输出:"30910,5,149.248.50.197"

分析

观察IP报文头的字符串表示header,可知header

  • 有空格,
  • 每个空格之间的内容是1个字节,以16进制表示。

注意到题目要求解析的“标志位”占3位,不是4的倍数。 因此,代码如果能将16进制表示转为2进制表示,那么才容易从header选出代表标志位的子序列。

笔者2进制表示的思路有两种:

  1. 使用无符号整数数组,
  2. 使用只含有'0''1'的字符串。

第1种思路和现实情景中处理IP报文头的代码逻辑是一致的。 由于报文头中存在像标志位这种长度较小的字段, 代码必然需要使用与运算选出字段,还可能需要使用右位移运算将字段的最低位移动至第1位。 这种思路实现起来有些麻烦,且不方便debug。

第2种思路实现起来较为直观。代码先将header转换为'0''1'串, 然后根据题目要求,从串中截取出所需子串,而不需要使用位运算。 不过最后还要将选取的子串转化为整数。 笔者采用该思路。

题解

#include <array>
#include <map>
#include <sstream>
#include <string>

constexpr auto idx2bin { []() {
    std::array<std::array<char, 5>, 16> tmp {};
    for (int i = 0; i != 16; ++i)
        for (int j = 0; j != 4; ++j)
            tmp[i][j] = i & 8 >> j ? '1' : '0';
    return tmp;
}() };

int hex2idx(char hex)
{
    static std::map<char, int> memo;
    auto it = memo.find(hex);
    if (it != memo.end())
        return it->second;
    return memo[hex] = hex & 16 ? hex - '0' : (hex & 7) + 9;
}

std::string solution(const std::string& header)
{
    std::string bits;
    for (auto&& c : header)
        if (c != ' ')
            bits += idx2bin[hex2idx(c)].data();
    std::stringstream ans;
    ans << std::stoi(bits.substr(16, 16), nullptr, 2) << ',' << std::stoi(bits.substr(48, 3), nullptr, 2) << ','
        << std::stoi(bits.substr(128, 8), nullptr, 2) << '.' << std::stoi(bits.substr(136, 8), nullptr, 2) << '.'
        << std::stoi(bits.substr(144, 8), nullptr, 2) << '.' << std::stoi(bits.substr(152, 8), nullptr, 2);
    return ans.str();
}