语言环境无关“ATOF”?(Locale-independent “atof”?)

2019-07-03 18:25发布

I'm parsing GPS status entries in fixed NMEA sentences, where fraction part of geographical minutes comes always after period. However, on systems where locale defines comma as decimal separator, atof function ignores period and whole fraction part.

What is the best method to deal with this issue? Long/latitude string in stored in character array, if it matters.

Example Code:

m_longitude = atof((char *)pField); 

Where

pField[] = "01000.3897"; 

Cross-platform project, compiled for Windows XP and CE.

Comment to solution:

Accepted answer is more elegant, but this answer (and comment) is also worth knowing as a quick fix

Answer 1:

你总是可以使用(模错误检查):

#include <sstream>
...

float longitude = 0.0f;
std::istringstream istr(pField);

istr >> longitude;

标准输入输出流默认情况下使用(这反过来应该被初始化为经典的(美国)区域)全球区域。 因此,上述一般应工作,除非有人事先已经改变了全球的区域设置到别的东西,即使你在一个非英语的平台上运行。 为了绝对确保所需的语言环境时,创建一个特定的语言环境和“灌输”与区域物流从中读取之前:

#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到分钟(但我想你已经知道了)。



Answer 2:

一个讨厌的解决方案,我已经做了一次,是sprintf() 0.0F和抓住从输出的第二个字符。 然后在输入字符串替换“” 通过该字符。 这解决了逗号情况,但是如果一个区域设置定义其他的小数点分隔符也将工作。



Answer 3:

任何理由,你为什么不能做的setlocale的ATOF之前“C”和事后恢复的语言环境? 也许我误解了这个问题...



Answer 4:

你可以通过在阵列中的所有字符进行迭代,并与交换任何非数字. 字符,只要坐标是在其中应该工作number-single_delimiter_character_-number格式。



Answer 5:

你真的需要获得NUMERICS语言环境的行为? 如果不

setlocale(LC_ALL|~LC_NUMERIC, "");

或等值使用std ::区域构造函数。



Answer 6:

一些解决方案上面似乎没有工作,所以我提出这是一个完美的解决方案failproof。 只要复制粘贴此功能,并使用它来代替。

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;
}


Answer 7:

我认为最简单的回答这个具体的问题是使用的版本atof()这需要一个C语言环境参数:

_locale_t plocale = _create_locale( LC_ALL, "C" );

double result = _atof_l( "01000.3897", plocale );

_free_locale( plocale );

这可以让你不惹流或全局区域设置,或与操纵字符串,在所有。 只要创建所需的Locale对象做所有的处理与再释放它,当你完成。



文章来源: Locale-independent “atof”?
标签: c++ locale atof