我正在解析固定NMEA句子中的GPS状态条目,其中地理分钟的一小部分总是在句点之后。但是,在locale将逗号定义为小数分隔符的系统上, atof 函数会忽略句点和整数小数部分。
处理此问题的最佳方法是什么?存储在字符数组中的长/纬度字符串,如果重要的话。
示例代码:
m_longitude = atof((char *)pField);
哪里
pField[] = "01000.3897";
跨平台项目,为Windows XP和CE编译。
对解决方案的评论:
接受的答案更优雅,但this回答(和评论)也值得快速解决
答案 0 :(得分:16)
您可以随时使用(模数错误检查):
#include <sstream>
...
float longitude = 0.0f;
std::istringstream istr(pField);
istr >> longitude;
默认情况下,标准iostream使用全局语言环境(而后者应该初始化为经典(美国)语言环境)。因此,除非有人以前将全局语言环境更改为其他内容,否则上述内容应该可以正常工作,即使您在非英语平台上运行也是如此。为了确保使用所需的语言环境,请创建一个特定的语言环境,并在读取该语言环境之前“填充”该流:
#include <sstream>
#include <locale>
...
float longitude = 0.0f;
std::istringstream istr(pField);
istr.imbue(std::locale("C"));
istr >> longitude;
作为旁注,我通常使用正则表达式来验证NMEA字段,将字段的不同部分提取为捕获,然后使用上述方法转换不同的部分。 NMEA经度字段中小数点前面的部分实际上格式化为“DDDMM.mmm ..”,其中DDD对应度数,MM.mmm到分钟(但我猜你已经知道了)。
答案 1 :(得分:7)
我曾经做过的一个令人讨厌的解决方案是sprintf()
0.0f并从输出中获取第二个字符。然后在输入字符串中替换'。'通过那个角色。这解决了逗号大小写,但如果语言环境定义了其他小数分隔符,也可以使用。
答案 2 :(得分:4)
这个问题很旧,但是与此同时,在C ++中,我们得到了一个“与语言环境无关”的atof:
在c ++ 17中添加的 std::from_chars
(及其同级std::to_chars
)提供了与语言环境无关的浮点扫描(和格式设置)。它们位于标题<charconv>
中。
您可以在此处了解有关它们的更多信息:
https://en.cppreference.com/w/cpp/utility/from_chars
https://en.cppreference.com/w/cpp/utility/to_chars
我建议Stephan T. Lavavej很好地谈论这两个工具,这是他谈论使用std :: from_chars的部分的链接: https://youtu.be/4P_kbF0EbZM?t=1367
还有我的一个简短示例:
#include <charconv>
#include <iostream>
#include <system_error>
int main()
{
char buffer[16] { "123.45678" };
float result;
auto [p, ec] = std::from_chars(std::begin(buffer), std::end(buffer), result);
if(ec == std::errc{})
std::cout << result;
}
不幸的是,就今天(2020年6月6日)而言,仅MSVC支持使用浮点类型的这些功能。高效地实施它们是一个大问题。
答案 3 :(得分:2)
为什么你不能在atof之前做setlocale“C”并之后恢复语言环境?也许我误解了这个问题......
答案 4 :(得分:0)
您可以遍历数组中的所有字符,并使用.
字符交换任何非数字,只要坐标为number-single_delimiter_character_-number
格式,该字符就可以正常工作。
答案 5 :(得分:0)
你真的需要获得数字的语言环境行为吗?如果不是
setlocale(LC_ALL|~LC_NUMERIC, "");
或等效使用std :: locale构造函数。
答案 6 :(得分:0)
上面的一些解决方案似乎没有用,所以我认为这是一个完全防故障的解决方案。只需复制粘贴此功能并改为使用它。
float stor(const char* str) {
float result = 0;
float sign = *str == '-' ? str++, -1 : 1;
while (*str >= '0' && *str <= '9') {
result *= 10;
result += *str - '0';
str++;
}
if (*str == ',' || *str == '.') {
str++;
float multiplier = 0.1;
while (*str >= '0' && *str <= '9') {
result += (*str - '0') * multiplier;
multiplier /= 10;
str++;
}
}
result *= sign;
if (*str == 'e' || *str == 'E') {
str++;
float powerer = *str == '-'? str++, 0.1 : 10;
float power = 0;
while (*str >= '0' && *str <= '9') {
power *= 10;
power += *str - '0';
str++;
}
result *= pow(powerer, power);
}
return result;
}
答案 7 :(得分:0)
我相信这个具体问题的最简单答案是使用atof()
的版本,该版本采用C语言环境参数:
_locale_t plocale = _create_locale( LC_ALL, "C" );
double result = _atof_l( "01000.3897", plocale );
_free_locale( plocale );
这使您可以根本不弄乱流,全局语言环境或操作字符串。只需创建所需的区域设置对象即可完成所有处理,然后在完成后将其释放。