International settings. 2 questions : Can it better?

Hi all!

This is the problem : Sometimes decimal point is defined as a '.', sometimes as ','. How can I check wich one is defined? At this moment I do it like this, but is there a better way to do it? (the machine connected by RS232 always sends it's numbers in strings by decimal point defined as '.')

 try
  Result    := Copy(Data,Pos(Teken,Data)+Stap,4);
   TestFloat := StrToFloat(Result);                
 except                                            
  on E:EConvertError do
    Result[Pos('.',Result)] := ',';
 end;

Another question :
 I use a TStringlist to put 21 numbers in.
 With the commatext property I can easy put these values
 in a inifile as a total string. Like this :

 if LightCurveRead then begin
  SDF_List := TStringList.Create;
  for i := 0 to 20 do    SDF_List.Add(GridLDensities.Cells[i,1]);
  LightCalibration := SDF_List.CommaText;
  IniLCalibration.Value := LightCalibration;
  SDF_List.Clear;
  SDF_List.Free;

The problem occurs sometimes when you try to read this string :
 1. If you have put numbers with '.' -> no problem occurs
 2. If you have put numbers with ',' -> first number isn't
    read in correctly.

How does the string looks like?
 1. IniLCalibration=0.16,0.16,0.17, ...........
 2. IniLCalibration="0,16","0,16","0,17", .......
How is it read in?
 1. correctly -> first number 0.16,
                 second number 0.16,
                 third number 0.17, ...
 2. not correct -> first number is 0
                   second number '16"' -> error not number!
                   third number 0,16 ,
                   fourth number 0,17 , ....

 I solved this problem this way :

 { Following code is a tempory solution
    Following occurs : if decimal is comma then you need to add ' in beginning and end of string, otherwise first number gives error }
  if Copy(SDF_List.Strings[0],2,1) = ',' then
   IniLCalibration.Value :=      char(39)+LightCalibration+char(39)
  else IniLCalibration.Value := LightCalibration;

This works! Seems that you have to put ' in the beginning and the end of the string (case 2!).
Well, even it works, I don't like this method! Am I doing something wrong here, or is this an error from Borland?
Does someone knows a better solution?

Thanks, ZifNab
LVL 8
ZifNabAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

JimBob091197Commented:
Hi

In answer to your first question, you can check what the Decimal character is by reading from the registry:
HKEY_CURRENT_USER\Control Panel\International\
Use "Reg.ReadString('', 'sDecimal', '.');" to get the decimal character.

JB
0
JimBob091197Commented:
Hi again

Regarding your 2nd question, I tried the following:

procedure TForm1.Button1Click(Sender: TObject);
var
  s: TStringList;
begin
  s := TStringList.Create;
  s.CommaText := '"0,15","0,16","0,17"';
  Memo1.Lines.Assign(s);
  s.Free;
end;

This works correctly on my PC, i.e. The TMemo gets 3 lines:
0,15
0,16
0,17

It also works if I change the CommeText line to:
  s.CommaText := '0.15,0.16,0.17';

(I use Delphi 3.)

JB
0
itamarCommented:
1st question:
 - I think it's better using the variable declared in SysUtils unit: DecimalSeparator.

2nd question:

- It doesn't seem to be a bug from borland. The string in commatext is delimited by comma, there is no way to deal with strings that contains a comma itself. It would be impossible to parse without a workaround like that.
The problem, i guess, it's because you have different settings when you SAVE the strings and when you LOAD it ! Remember that  the comma character used as decimal separator can NOT be used in float operations. Perhaps i could help further if you give me more details, because here in Brazil we have a lot of experience with different (comma) decimal separator ;)
0
Angular Fundamentals

Learn the fundamentals of Angular 2, a JavaScript framework for developing dynamic single page applications.

ZifNabAuthor Commented:
Hi all,

10x for responding.

JB : Reading from registry : what if entry doesn't exists?

   Now, you put '.' when it doesn't exist, but what if it
   has to be a ','.
     
     Is the entry the same on Win NT?
     What about Win 3.x

* Yes both strings work also with my program, but :
   When I save to ini file : "0,16","0,17","0,18"
    This appears in ini file : "0,16","0,17","0,18"
   When I save to ini file : 0.16,0.17,0.18
    This appears in ini file : '0.16,0.17,0.18'
* It's even weirder!
   + I changed my program -> if strings are like this
      "0,16","0,17","0,18" I save them with extra '
   + I reload from ini -> gives me an error!
      BUT
   + save the ini (also with extra ')
     close the program and rerun it
      -> it doesn't gives me an error!
 
* Itamar

   DecimalSeperator : how can I use it?

   What more information do you need?

    -> Depending from computer I send '.'-numbers or ','-numbers
       top ini file.
    -> This I do with putting each number in TStringList
    -> With CommaText i've got now a Comma delimited string.
   
    -> Problem occurs with "0,16","0,17",...
       -> Can't read first number, but others it reads!
          So it knows to handle with ','-numbers.
       If string is '"0,16","0,17"' it doesn't has a problem.
       BUT the problem is that with these ','-numbers it DOESN'T
       write the string with ' to a file. And it does write a
       string with '.'-numbers to a file WITH '.
       WHY does it do that?


 
0
itamarCommented:
Zif, the DecimalSeparator is just there. It contains the decimal separator char in the current configuration of Windows, so if you do:
Edit1.Text := DecimalSeparator;

You can see the current char in the registry.
But, i think this will not help very much.
0
itamarCommented:
Still thinking on it...
0
JimBob091197Commented:
Hi

It appears that if the registry value for the Decimal Separator is missing, it defaults to "."

With the 2nd problem, couldn't you ALWAYS save with ' on each end, and ALWAYS strip ' off each end after reading from Ini file?  ( I realize that you cant type "MyStrngList.Text := '''' + MyStringList.Text + '''';" because Delphi will put the last ' on a new line...  How are you saving to the INI file?)

JB
0
ZifNabAuthor Commented:
Hi!

Haha! Thruth, you can't type '''+MyStringList.Text+''';
I found that out too. That's why I use char(39).
Like this char(39)+MyStringList.Text+Char(39);
and this is my code :

 if Copy(SDF_List.Strings[0],2,1)=',' then
   IniCalibration.Value := char(39)+LightCalibration+Char(39);

So, now if I have "0,16","0,17" it puts two ' to the string.
But then I've the problem like I said in the comment before. It
will only read the string correct if I exit the program. After that the string will always be read so in fact it's not such a big deal. But, I find it strange.

I have to check for the comma, because when 0.16,0.17 is the string it already puts ' to the string!

I also have the problem when reading these strings in the analysing program. Here I also have to determine if , or . is send in.
0
itamarCommented:
I am suposing that when you "read" the INI file you put the string in a TStringList again and then, from this to a Grid.
Am I right ?

0
ZifNabAuthor Commented:
Yes, I put the string back in a stringList then I transfer every string to a number (float) and with this I can show a calibration curve or I have a curve of that machine for that particular day.
I'm also finding other problems now. It's with the date format. Some computers use - between the days and months, some /. Damn these international settings make it hard.
0
itamarCommented:
YES ! Globalization NOW !
As i thought (and said) in my first comment:
"...The problem, i guess, it's because you have different settings when you SAVE the strings and when you LOAD it ! ..."
I was thinking about someway to avoid this kind of trouble, for example: use the Format function to store the values in scientific notation, or something like that, but wasn't successfull yet :{
0
ZifNabAuthor Commented:
Hi all,
Seems that there isn't an easy way to help me out.

Well, I found another solution. Can I set (for my application ONLY!) the international setting to one and only one? Or can I set that all the floating points in my program will be with a point? Is this easy to implement?

Regards,
ZifNab.
0
ZifNabAuthor Commented:
How does Excel work with these different international settings?
0
ZifNabAuthor Commented:
Maybe I just save the Decimal and Date seperator to the Ini-file and then depending on that I do different readings.
0
itamarCommented:
Hi ZifNab,
i think i have a good sugestion to the date problem.
If you save the date fields (or cells) in internal format you'll be independent of the separator and external format (dd/mm/yy or mm/dd/yy) settings. Some thing like that:

procedure WhenYouSave(...);
var VarToSave: string;
begin
  ...
  VarToSave := FloatToStr(StrToDate(Edit1.Text));
  ...
end;

procedure WhenYouRead(...);
var ReadDate: TDateTime;
begin
  ...
  ReadDate := StrToFloat(VarToSave);
  ...
end;

Another advantage: disk space, because to a date, e.g., '13/11/1963' you will save the string '23328'.
If i couldn't make me clear, place a comment.
Still thinking about the number problem, but i think this will follow the same guidelines.
0
ZifNabAuthor Commented:
Hi Itamar!

Thanks! You're correct, that's a way to get rid of the different date settings. Thanks a lot!
Hope, you can come up with a solution of the decimal problem.

Regards,
ZifNab;
0
itamarCommented:
Indeed i already have a fast one, but i am not completely happy with that. I'm looking for a clever one.
Anyway, here is it:

Make a Replace function (Mumps have a native one) that changes every ocurrency of a substring in a string for another one. Something like:

Function Replace(Source:Float; SubStr, NewString: string): string;

Apply this function to all values you have to save in a way you can have standards decimal and thousand separator, this way:

   Suppose YourValue = 1.234,56

   ValueSave := Replace(YourValue,DecimalSeparator,'d');
   ValueSave := Replace(YourValue,ThousandSeparator,'t');
Obs:
-Don't forget to include the SysUtils unit in the uses clause !

Now you have a string '1t234d56'
Then you'll have to make another function to "translate" this string putting back the DecimalSeparator and ThousandSeparator of YOUR machine and convert to float.
I know the function can be more smart and change the 2 damn ocurrencys in a single call, but now optimization is up to you.
It's just a general idea.

Hei Zif, if you take this as an answer, make me know so i can put it as is and get the points. BTW, what about increasing  the points ? It's not properly an "easy" question, is it ?  ;)

IHTH...
0
ZifNabAuthor Commented:
Itamar,

 I was already intending to increase the points of this question.  Send your two solutions as an answer and I'll grade it.
0
itamarCommented:
DATE PROBLEM:
 
If you save the date fields (or cells) in internal format you'll be independent of the separator and external format (dd/mm/yy or mm/dd/yy) settings. SOme thing like that:                      procedure WhenYouSave(...);
var VarToSave: string;
begin
   ...
   VarToSave := FloatToStr(StrToDate(Edit1.Text));
   ...
end;

procedure WhenYouRead(...);
var ReadDate: TDateTime;
begin
  ...
  ReadDate := StrToFloat(VarToSave);
  ...
end;

Another advantage: disk space, because to a date, e.g., '13/11/1963' you will save the string '23328'.

NUMBER PROBLEM:

Make a Replace function (Mumps have a native one) that changes every ocurrency of a substring in a string for another one. Something like:

Function Replace(Source:Float; SubStr, NewString: string): string;

Apply this function to all values you have to save in a way you can have standards decimal and thousand separator, this way:

Suppose YourValue = 1.234,56

ValueSave := Replace(YourValue,DecimalSeparator,'d');
ValueSave := Replace(YourValue,ThousandSeparator,'t');
Obs:
-Don't forget to include the SysUtils unit in the uses clause !

Now you have a string '1t234d56'
Then you'll have to make another function to "translate" this string putting back the DecimalSeparator and ThousandSeparator of YOUR machine and convert to float.
I know the function can be more smart and change the 2 damn ocurrencys in a single call, but now optimization is up to you.

It's just a general idea.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ZifNabAuthor Commented:
Thanks itamar! I'll try to help you if you are having problems!
0
ZifNabAuthor Commented:
Hi itamar,

I was just thinking about second solution. You use DecimalSeperator and ThousandSeperator in your example, but isn't this a constant determined on the machine you compile the program? Or is it 'intelligent', does it uses the definition on the machine the program is working on?
Otherwise I have to open the registry.
0
itamarCommented:
It's an intelligent constant. It reflects the current settings in the machine you RUN the program.!
0
ZifNabAuthor Commented:
Thanks Itamar!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.