?
Solved

Recognizing both decimal separators (,.)

Posted on 2011-06-20
8
Medium Priority
?
956 Views
Last Modified: 2012-05-11
Currently I need to send software generated data files to countries with decimal separators other than my own. Delphi (Windows) does not handle this transparently. Is there a way to force the VCL (StrToFloat, etc) to handle EITHER ',' or '.' as a separator? I'd rather not have to do the conversions explicitly in my code, or create multiple country-speciific data files. Thanks in advance for your help.
0
Comment
Question by:TracerXXX
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
  • 2
  • +1
8 Comments
 
LVL 24

Expert Comment

by:jimyX
ID: 36004258
You can set the Decimal Separator in your application, so all the conversion will be based on the selected symbol:
procedure TForm1.FormCreate(Sender: TObject);
begin
  DecimalSeparator := ','; // or '.'
end;
0
 

Author Comment

by:TracerXXX
ID: 36004317
jimyX,

I considered that but I'm guessing that my foreign users wouldn't like being forced to use my separator. I was hoping there was a way to tell the VCL to handle both. It was worth asking the question :-)

Thanks
0
 
LVL 24

Accepted Solution

by:
jimyX earned 1000 total points
ID: 36004588
If the data, which is going to be sent, has been generated by you (or at least you know the locale settings) then you can replace the data on every PC to match the local configuration (i.e. you can have your application starting by checking the current regional configuration and convert the data accordingly).

For example let's say you are sending the following number to Latin locale PC:
1,234.5

On the Latin locale PC the number should be 1.234,5 so you start by detecting the DecimalSeparator and the ThousandSeparator then replace your data before it's processed or handled on that PC.
So in three steps, you will be replacing the '.' to a unique char, let's assume '#', and then convert the ',' to the Thousand Separator and finally the '#' to the Decimal Separator.
var
  MyNum:Float;
  Temp:String;
begin
  Temp := StringReplace('1,234.5', '.', '#', [rfReplaceAll]);
  Temp := StringReplace(Temp, ',', ThousandSeparator, [rfReplaceAll]);
  Temp := StringReplace(Temp, '#', DecimalSeparator, [rfReplaceAll]);
  MyNum := StrToFloat(Temp);

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 25

Assisted Solution

by:epasquier
epasquier earned 1000 total points
ID: 36004745
you have to normalize in your file and other data-exchange mechanism, while your application is using the standard application settings. So you need 2 conversion routines of the kind of JimyX 's.
function NormalizedToInternalFloatString(const aFloatStr):String;
begin
  Result:= StringReplace(aFloatStr, '.', '#', [rfReplaceAll]);
  Result:= StringReplace(Result, ',', ThousandSeparator, []);
  Result:= StringReplace(Result, '#', DecimalSeparator, []);
end;

function InternalToNormalizedFloatString(const aFloatStr):String;
begin
  Result:= StringReplace(aFloatStr, DecimalSeparator, '#', []);
  Result:= StringReplace(Result, ThousandSeparator, ',', []);
  Result:= StringReplace(Result, '#', '.', []);
end;

and go on with helper functions : Normalize String <=> Internal Float

function NormalizedStringToFloat(const aFloatStr):Double;
begin
 Result:=StrToFloat(NormalizedToInternalFloatString(aFloatStr));
end;

function FloatToNormalizedString(value:Double):String;
begin
 Result:=InternalToNormalizedFloatString(FloatToStr(Value));
end;

Open in new window

0
 

Author Comment

by:TracerXXX
ID: 36010331
Thanks guys. It wasn't the answer I was hoping for but it looks like the approach I'm going to take.
0
 
LVL 32

Expert Comment

by:Ephraim Wangoya
ID: 36013601

I got into this late but I would use a totally different method.

Remember that delphi has overloaded versions of functions such as StrtoFloat one of which takes TFormatSettings as second parameter.

So long as you set your TFormatSettings properly, you can use any separators you wnat and avoid doing a StringReplace or similar method to modify already generated data
0
 

Author Comment

by:TracerXXX
ID: 36013737
Thanks ewangoya, I'll take a look at your approach.
0
 
LVL 25

Expert Comment

by:epasquier
ID: 36017662
ewangoya : you are totally right, and that could be a good choice for Tracer.

Before your intervention, we have emphasized on the general problem to transcode data between external and internal format.
That generic problem involves a Transcoder class (here, we haven't taken the trouble to make a class out of it, but if there was other such needs then it might be good to cross that bridge) and for each data TWO functions are needed, a getter and a setter ( getter : internal => external , setter : external => internal )
If you only stick to string formatted data, and your format those strings with patterns that are compatible with TFormatSettings, then implementing those getter and setter with use of TFormatSettings is completely acceptable.

But IMO, I would not use a string format for external storage/communication. What about using BINARY formats for integer/float/datetime... values ? The conversion is generally easier (nothing to do) and will work the same on all systems (whatever the localized parameters). I don't understand that worldwide tendency to store/send everything as human-readable format. It helps edit data, Ok. But would data need that much editing if we hadn't to implement and debug the complex getters/setters ?
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

719 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question