在 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 的东西,具体取决于 sscanf
、setjmp
、longjmp
、(以及其他几个)可能无法正常工作。
编辑:
@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
X
和 Y
要么在 [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);
希望对您有所帮助,恐怕无法使用与您相同的编译器,很难解决您的问题。
我想要的:
要解析一个 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 的东西,具体取决于 sscanf
、setjmp
、longjmp
、(以及其他几个)可能无法正常工作。
编辑: @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
X
和Y
要么在[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);
希望对您有所帮助,恐怕无法使用与您相同的编译器,很难解决您的问题。