C++ 无分隔符键值对字符串拆分:解决strtof误识别十六进制问题
问题根因
标准C库的strtof默认支持十六进制浮点数语法,会将0x/0X开头的序列识别为十六进制数值,而该场景中0后面紧跟的X是下一个键的名称,不属于当前数值的组成部分,因此触发了错误解析。
解决方案
方案1:提前确定数值边界,截断后再解析
该场景的键值对规则为单字母作为键,键后紧跟仅由数字、小数点、可选正负号组成的浮点数值,数值中不会出现字母字符,因此可以提前划定数值的解析范围:
- 每次先读取当前位置的1个字母作为键,指针后移1位
- 从当前指针位置开始向后遍历,直到遇到非
0-9/./+/-的字符,该位置即为当前数值的结束边界 - 在结束边界位置临时写入
\0,调用strtof解析这段截断后的字符串,解析完成后恢复原位置的字符(若需要保留原字符串) - 把指针移动到结束边界位置,重复上述流程解析下一个键值对
该方案完全避开了strtof识别0X前缀的场景,不会出现误判。
方案2:利用strtof的endptr参数修正解析结果
如果不想修改原字符串,可以利用strtof的第二个输出参数判断是否触发了十六进制解析,手动修正结果:
char *parse_ptr = 待解析的字符串首地址; while (*parse_ptr != '\0') { // 读取单字母键 char key = *parse_ptr++; char *num_end; float value = strtof(parse_ptr, &num_end); // 判断是否错误将0X识别为十六进制前缀 if (parse_ptr[0] == '0' && (parse_ptr[1] == 'X' || parse_ptr[1] == 'x') && num_end > parse_ptr + 1) { // 修正:当前数值为0,数值结束位置为0的下一位 value = 0.0f; num_end = parse_ptr + 1; } // 此处处理解析得到的键值对:key和value parse_ptr = num_end; }
该方案改造成本极低,仅需要在原有strtof调用逻辑后增加一段判断修正逻辑即可。
方案3:自定义十进制浮点解析函数
如果场景中确定不会用到十六进制数值,可以自行实现轻量的浮点解析函数,仅处理十进制的数字、小数点、正负号规则,完全不识别0x前缀,从根源上避免该问题。
内容的提问来源于stack exchange,提问作者Max Peglar-Willis
相关产品推荐
相关产品推荐

