在 C++ 中拆分字符串

Splitting String in C++

我想要的:

要解析一个 MAC 地址字符串并获得一个包含六个 uint8_t 值的数组,输入类似于 string str = "01:23:45:AB:CD:EF";.

我尝试过的(但没有成功):

sscanf(str.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);

为什么它不起作用: 我正在 Arduino IDE 的帮助下为 ESP8266 Wi-Fi 模块编程。尽管 Arduino 板的官方内核支持 sscanf(),但 ESP8266 的内核不支持。 (The solution to the issue given on GitHub 不起作用,如 nicjohnston 所述。)

最不喜欢:

任何占用过多 RAM、CPU 周期或程序存储空间的东西。
还有一些使用或 directly/indirectly 的东西,具体取决于 sscanfsetjmplongjmp、(以及其他几个)可能无法正常工作。

编辑: @m.s的回答。下面是绝对正确的,但我意识到在我设计了自己的代码(如下所示)之后。

for(uint8_t i=0; i<5; i++)
  mac[i]=strtol(Serial.readStringUntil(':').c_str(),NULL,16);
mac[6]=strtol(Serial.readStringUntil('\n').c_str(),NULL,16);

您可以使用正则表达式提取内容并存储在数组中。然后解析数组以获取相应的 uint8_t 等价物。

正则表达式可以是这样的:[0-9A-F][0-9A-F]

您可以参考此参考文献 link 以了解有关正则表达式及其使用方法的更多详细信息:http://www.cplusplus.com/reference/regex/regex_search/

在 C++ 中,regex_search 允许搜索正则表达式模式并可能提取搜索到的(或匹配的)模式。

在您的特定用例中,您可以简单地遍历字符串并将十六进制子字符串转换为数字,如下所示:

  • 每个子字符串正好由两个十六进制字符组成;让子字符串表示为 XY
  • XY 要么在 [0-9] 内,要么在 [A-F] 内,其中 A 表示 10, B 表示 11, 等等(十进制)
  • 从 ASCII 值到其中一个字符的数字含义的转换取决于字符来自哪个字符集:

  • 如果一个字符 c 来自 [0-9],它的十进制含义是 c-'0',即减去偏移量以便应用以下映射 '0'=>0, '1' => 1, ...

  • 如果一个字符c来自[A-F],映射可以表示为c-'A'+10

  • 每个子字符串 XY 的数字十进制值 v 然后计算如下: v=X*16 + Y

  • 子字符串由单个字符分隔(此处为 :,但这无关紧要)

以下代码实现了这些想法:


#include <string>
#include <cstdlib>

std::uint8_t getNum(char hexChar)
{
    if(hexChar >= '0' && hexChar <= '9')
    {
        return hexChar - '0';
    }
    return (hexChar-'A'+10);
}

int main()
{
    std::uint8_t mac[6];
    std::string str = "01:23:45:AB:CD:EF";

    std::uint8_t j = 0;
    for(std::uint8_t i = 0; i<6; ++i)
    {
        mac[i] = getNum(str[j])*16 + getNum(str[j+1]);
        j+=3; // get to the next substring
    }
}

我来晚了,m.s.的回答是正确的。

我的回答有点不同,因为它使用从一串字符计算十六进制,并使它更像 c++11。 虽然我不确定您的 ESP8266 模块是否支持它,但希望它能有所帮助。

#include <string>
#include <array>

std::array< uint8_t, 6> MAC_fromStringToArray(const std::string& str)
{
    std::array< uint8_t, 6> ret ;

    for (auto i = 0; i < 6; i++)
    {
        ret[i] = std::stoi(str.substr((i * 3), 2), nullptr, 16);
    }

    return ret;
}

int main()
{
    std::string str = "01:23:45:AB:CD:EF";

    std::array< uint8_t, 6> mac = MAC_fromStringToArray(str);

    return 0;
}

编辑:由于似乎不可用,我将其更改为传统数组。

uint8_t * MAC_fromStringToArray(const std::string& str, uint8_t arr[])
{
    for (int i = 0; i < 6; i++)
    {
        arr[i] = std::stoi(str.substr((i * 3), 2), nullptr, 16);
    }

    return arr;
}

需要不同的称呼:

uint8_t arr[6]; 

MAC_fromStringToArray(str, arr);

希望对您有所帮助,恐怕无法使用与您相同的编译器,很难解决您的问题。