AnsiString для двойного C++

Я пытаюсь преобразовать AnsiString к double, но после запуска программы он говорит: "20.60 не является допустимой плавающей точкой".

AnsiString Temperatur

RE_Temperatur->Text = Temperatur;

Chart1->Series[0]->AddXY(DT_Uhrzeit->Time, RE_Temperatur->Text.ToDouble(), 
"", clRed);

Значение для Temperatur приходит из соединения SerialPort с моего Arduino и доставляет что-то вроде 20.60 и так далее. Когда я обрезаю строку до первых двух цифр, она работает нормально. Угадай . как-то связано с ошибкой, но я не знаю, как ее решить.

РЕДАКТИРОВАТЬ // Я сейчас попытался просто заменить "." с "," со следующим кодом:

    RE_Temperatur->Text = StringReplace(RE_Temperatur->Text, ".", ",", 
    TReplaceFlags() << rfReplaceAll);

Теперь я получаю сообщение об ошибке "20,60 не является допустимой плавающей точкой". Это так расстраивает:/

3 ответа

Решение

Попробуйте этот простой кусок кода в новой консольной программе:

AnsiString Temperatur = "12.45"; // locale independent
AnsiString Temperatur2 = "12,45"; // correct in my German locale

double temp = StrToFloat(Temperatur, TFormatSettings::Invariant());
double temp2 = StrToFloat(Temperatur2); // In my case: German locale!

printf("%8.4f %8.4f\n", temp, temp2);

Выход:

 12.4500  12.4500

Вы можете видеть, что это работает как ожидалось. Обратите внимание, что в моей системе запятая является десятичным разделителем для локали, и, тем не менее, этот код прекрасно работает с точкой в ​​качестве десятичного разделителя из-за настроек инвариантного формата.

Так что делайте свой выбор: используйте TFormatSettings::Invariant() если вам нужна независимость от локали, но не используйте ее, если вы хотите использовать десятичный разделитель для локали пользователя.

Вы можете использовать StrToFloat, у него есть вторая версия, которая принимает TFormatSettings объект, который вы можете использовать для указания конкретного DecimalSeperator, Кстати, он не возвращает float, так как его имя может означать, что он возвращает Extended ака long double,

Держу пари, что ваша проблема - десятичная точка. Используемый для него символ является одной из переменных среды Windows и может варьироваться от компьютера к компьютеру. Есть звонки winapi, чтобы получить его, но я не помню их...

Проблема с AnsiString("1.23").ToDouble() в том, что catch/try не поймает исключение (по крайней мере на моем компиляторе BDS2006). Есть обходные пути. я использую atoi() вместо этого это не сбой, а скорее усечение до целого числа, когда присутствует недопустимый символ, поэтому его можно использовать для определения правильного знака десятичной точки и преобразования:

char _floating_point_char=' ';         // decimal point separator
AnsiString   strnum (AnsiString s,int sig=1,int pnt=1,int hex=0,char dot=_floating_point_char);
double       str2num(AnsiString s,int sig=1,int pnt=1,int hex=0,char dot=_floating_point_char);

AnsiString strnum(AnsiString s,int sig,int pnt,int hex,char dot)
    {
    if (dot==' ')
        {
        float x;
        x=atof("0.5"); if (x>=0.25) _floating_point_char='.';
        x=atof("0,5"); if (x>=0.25) _floating_point_char=',';
        dot=_floating_point_char;
        }

    int i,l,a,e,e0,exp=pnt;
    AnsiString q="";
    l=s.Length();
    if (hex) exp=0;     // exponent is e,E so it colide with hex e,E
    e0=0; for (i=1;i<=l;i++)
        {
        e=0;
        a=s[i];
        if ((a>='0')&&(a<='9'))       { e=1; q+=char(a  ); sig=0; }
        if ((a>='A')&&(a<='F'&&(hex))){ e=1; q+=char(a  ); sig=0; }
        if ((a>='a')&&(a<='f'&&(hex))){ e=1; q+=char(a  ); sig=0; }
        if ((a=='e')||(a=='E'))
         if (!hex)   { if (!exp) break; e=1; q+=char('e'); exp=0; sig=1; pnt=0; e0=0; }
        if (a=='+')  { if (!sig) break; e=1;               sig=0; }
        if (a=='-')  { if (!sig) break; e=1; q+=char(a  ); sig=0; }
        if (a=='.')  { if (!pnt) break; e=1; q+=char(dot); pnt=0; }
        if (a==',')  { if (!pnt) break; e=1; q+=char(dot); pnt=0; }
        if ((e0)&&(!e)) break;
        e0|=e;
        }
    if (q.Length()<=0) q="0";
    return q;
    }
double str2num(AnsiString s,int sig,int pnt,int hex,char dot)
    {
    return atof(strnum(s,sig,pnt,hex,dot).c_str());
    }

Это просто обнаружить, если . или же , является правильным, а затем заменить его в строке перед преобразованием... Грубая выборка правильного символа десятичной точки из winapi безопаснее, поскольку разделитель десятичной запятой может быть любым... Вы можете игнорировать hex Часть я использую это для любых видов чисел...

Другие вопросы по тегам