Locale-independent “atof”?

折月煮酒 提交于 2019-11-27 13:52:16

问题


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


回答1:


You could always use (modulo error-checking):

#include <sstream>
...

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

istr >> longitude;

The standard iostreams use the global locale by default (which in turn should be initialized to the classic (US) locale). Thus the above should work in general unless someone previously has changed the global locale to something else, even if you're running on a non-english platform. To be absolutely sure that the desired locale is used, create a specific locale and "imbue" the stream with that locale before reading from it:

#include <sstream>
#include <locale>

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

istr.imbue(std::locale("C"));
istr >> longitude;

As a side note, I've usually used regular expressions to validate NMEA fields, extract the different parts of the field as captures, and then convert the different parts using the above method. The portion before the decimal point in an NMEA longitude field actually is formatted as "DDDMM.mmm.." where DDD correspond to degrees, MM.mmm to minutes (but I guess you already knew that).




回答2:


A nasty solution I've done once is to sprintf() 0.0f and grab the second character from the output. Then in the input string replace '.' by that character. This solves the comma case, but would also work if a locale defined other decimal separators.




回答3:


Any reason why you can't do a setlocale "C" before the atof and restore the locale afterwards? Maybe I misunderstood the question...




回答4:


You could iterate through all the characters in the array and swap any non-numbers with a . character, which should work as long as the coordinates are in a number-single_delimiter_character_-number format.




回答5:


Do you really need to get locale behavior for numerics? If not

setlocale(LC_ALL|~LC_NUMERIC, "");

or the equivalent use of std::locale constructor.




回答6:


Some of the solutions above did not seem to work, so I propose this as a perfectly failproof solution. Just copy-paste this function and use it instead.

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:


I believe the simplest answer to this specific question would be to use the version of atof() which takes a C locale parameter:

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

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

_free_locale( plocale );

This allows you to not mess with streams, or the global locale, or with manipulating the string, at all. Just create the desired locale object to do all your processing with and then free it when you are finished.



来源:https://stackoverflow.com/questions/1333451/locale-independent-atof

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!