在C++中拆分字符串

Splitting String in C++

本文关键字:字符串 拆分 C++      更新时间:2023-10-16

我想要什么:

解析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的核心不支持。(正如nicjohnston所说,GitHub上给出的问题解决方案不起作用。)

最不优选:

任何占用过多RAM、CPU周期或程序存储的东西
此外,一些使用或直接/间接依赖于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);

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

  • 每个子字符串恰好由两个十六进制字符组成;设一个子串用XY表示
  • XY[0-9]内或在[A-F]内,其中A表示10B表示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
    }
}

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

正则表达式可能类似于:[0-9A-F][0-9A-F]

有关regex以及如何使用它的更多详细信息,您可以参考此参考链接:http://www.cplusplus.com/reference/regex/regex_search/

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

我来晚了,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);

希望它能有所帮助,我担心如果没有和你一样的编译器,很难解决你的问题。