Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: How to temporarily change DecimalSeparator


This question is answered.


Permlink Replies: 3 - Last Post: Feb 2, 2017 11:21 AM Last Post By: Remy Lebeau (Te...
Larry Johnson

Posts: 86
Registered: 6/7/14
How to temporarily change DecimalSeparator  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 1, 2017 1:29 AM
I am using the 32 bit VCL platform in XE4.

I have a .CSV file that I distribute with my software. The file uses numbers which have a period (.) as the decimal separator. I am using TryStrToFloat() to convert the text into a float. It appears this process is failing for my European customers because the default decimal separator is a comma (,). I believe DecimalSeparator is a Windows global variable and I do not know the implications of changing it. How can I check the DecimalSeparator and safely change it to a period (.) only temporarily while the code processes my .CSV file? Then I need to change it back to the default value?
Asger Joergensen

Posts: 370
Registered: 11/18/08
Re: How to temporarily change DecimalSeparator  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 1, 2017 2:50 AM   in response to: Larry Johnson in response to: Larry Johnson
Hi Larry

Larry Johnson wrote:

How can I check the DecimalSeparator and safely change it to a period (.) only
temporarily while the code processes my .CSV file? Then I need to change
it back to the default value?

I live in Denmark and I just tested this in Berlin and it works fine:

   wchar_t decSep = FormatSettings.DecimalSeparator;
   FormatSettings.DecimalSeparator = '.';
   String num = L"77.8";
   double dn = num.ToDouble();
   FormatSettings.DecimalSeparator = decSep;
 
   Edit1->Text = String(dn) + L"  " + num;


And this works in CB2009

   wchar_t decSep = DecimalSeparator;
   DecimalSeparator = '.';
   String num = L"77.8";
   double dn = num.ToDouble();
   DecimalSeparator = decSep;
 
   Edit1->Text = String(dn) + L"  " + num;


Best regards
Asger
Johannes Weinert

Posts: 90
Registered: 7/19/02
Re: How to temporarily change DecimalSeparator
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 1, 2017 4:56 AM   in response to: Asger Joergensen in response to: Asger Joergensen
Hi,

the other option would be to use
bool TryStrToFloat(const System::UnicodeString S, /* out */ double 
&Value, const TFormatSettings &AFormatSettings);

and hand over a manipulated copy of the global FormatSettings object.

If you use Asger's option below you could create a little class like

class TTempDecimalSeparator {
public:
   TTempDecimalSeparator( const System::WideChar new_decimal_separator )
     : OldDecimalSeparator( FormatSettings.DecimalSeparator )
   {
     FormatSettings.DecimalSeparator = new_decimal_separator;
   }
   ~TTempDecimalSeparator()
   {
     FormatSettings.DecimalSeparator = OldDecimalSeparator;
   }
private:
     const System::WideChar OldDecimalSeparator;
};


and use it at the beginning of the CSV processing function. So the
decimal separator will be restored even if an exception occurs.

Regards

Hans

Am 01.02.2017 um 11:50 schrieb Asger Joergensen:
Hi Larry

Larry Johnson wrote:

How can I check the DecimalSeparator and safely change it to a period (.) only
temporarily while the code processes my .CSV file? Then I need to change
it back to the default value?

I live in Denmark and I just tested this in Berlin and it works fine:

   wchar_t decSep = FormatSettings.DecimalSeparator;
   FormatSettings.DecimalSeparator = '.';
   String num = L"77.8";
   double dn = num.ToDouble();
   FormatSettings.DecimalSeparator = decSep;
 
   Edit1->Text = String(dn) + L"  " + num;


And this works in CB2009

   wchar_t decSep = DecimalSeparator;
   DecimalSeparator = '.';
   String num = L"77.8";
   double dn = num.ToDouble();
   DecimalSeparator = decSep;
 
   Edit1->Text = String(dn) + L"  " + num;


Best regards
Asger
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: How to temporarily change DecimalSeparator
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 2, 2017 11:21 AM   in response to: Johannes Weinert in response to: Johannes Weinert
Johannes wrote:

the other option would be to use

bool TryStrToFloat(const System::UnicodeString S, /* out */ double
&Value, const TFormatSettings &AFormatSettings);

Yes, using a TFormatSettings overloaded function is the correct solution,
however...

and hand over a manipulated copy of the global FormatSettings object.

Manipulating the global FormatSettings object is the WRONG approach. Use
a local TFormatSettings variable instead, eg:

// get default settings first...
 
TFormatSettings fmt;
// in XE and later, use this:
fmt = TFormatSettings::Create(GetThreadLocale());
// prior to XE, use this:
GetLocaleFormatSettings(GetThreadLocale(), Fmt);
 
// now customize as needed...
fmt.DecimalSeparator = '.';
 
// and finally use it...
String num = _D("77.8");
double dn = StrToFloat(num, fmt);
...


TFormatSettings has been around since Delphi 7 and C++Buider 2006.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02