Domanda

Sto analizzando le voci stato GPS con frasi NMEA fisso, dove frazione parte di minuti geografiche viene sempre dopo periodo. Tuttavia, nei sistemi dove locale definisce la virgola come separatore decimale, atof viene ignorato periodo e tutta la parte frazionaria.

Qual è il metodo migliore per affrontare questo problema? stringa Lungo / latitudine in memorizzato in array di caratteri, se è importante.

Esempio di codice:

m_longitude = atof((char *)pField); 

Dove

pField[] = "01000.3897"; 

progetto multipiattaforma, compilato per Windows XP e CE.

Commento alla soluzione:

risposta accettato è più elegante, ma questa risposta (e commentare) è anche la pena di conoscere come una soluzione rapida

È stato utile?

Soluzione

Si può sempre usare (modulo controllo degli errori):

#include <sstream>
...

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

istr >> longitude;

I iostreams standard utilizzano l'impostazione internazionale globale di default (che a sua volta dovrebbe essere inizializzato al classico locale (USA)). Così il sopra dovrebbe funzionare in generale a meno che qualcuno in precedenza ha cambiato il locale globale a qualcos'altro, anche se si sta eseguendo su una piattaforma non in lingua inglese. Per essere assolutamente certi che il locale desiderato viene utilizzato, creare un locale specifico e "infondere" il flusso con quel locale prima di leggere da esso:

#include <sstream>
#include <locale>

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

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

Come nota a margine, ho di solito usato espressioni regolari per convalidare i campi NMEA, estrarre le diverse parti del campo di cattura e quindi convertire le diverse parti che utilizzano il metodo di cui sopra. La parte prima del punto decimale in un campo NMEA longitudine in realtà è formattato come "DDDMM.mmm .." dove DDD corrispondono a gradi, mm.mmm di minuti (ma penso che si sapeva già che).

Altri suggerimenti

Una soluzione brutta che ho fatto una volta è quello di sprintf() 0.0f e afferrare il secondo carattere dall'output. Poi nella stringa di input sostituire '' da quel carattere. Questo risolve il caso virgola, ma potrebbe anche funzionare se un locale definito altri separatori decimali.

Qual è il motivo per cui non si può fare un setlocale "C "prima della atof e ripristinare le impostazioni internazionali dopo? Forse ho capito male la domanda ...

Si può scorrere tutti i caratteri nella matrice e scambiare eventuali non numeri con un carattere ., che dovrebbe funzionare finché le coordinate sono in un formato number-single_delimiter_character_-number.

Avete veramente bisogno di ottenere un comportamento locale per numerici? Se non

setlocale(LC_ALL|~LC_NUMERIC, "");

o l'uso equivalente di std :: locale costruttore.

Alcune delle soluzioni di cui sopra non sembra funzionare, quindi propongo questo come una soluzione perfettamente failproof. Basta copiare e incollare questa funzione e usarlo al posto.

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

Credo che la risposta più semplice a questa specifica domanda potrebbe essere quella di utilizzare la versione di atof() che prende un parametro C locale:

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

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

_free_locale( plocale );

Questo consente di non pasticciare con corsi d'acqua, o il locale globale, o con la manipolazione della stringa, a tutti. Basta creare l'oggetto locale desiderata a fare tutto il vostro trattamento con e poi liberarlo quando si è finito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top