Solved

International settings. 2 questions : Can it better?

Posted on 1997-11-14
23
196 Views
Last Modified: 2010-04-04
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
0
Comment
Question by:ZifNab
  • 11
  • 9
  • 3
23 Comments
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1350412
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
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1350413
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
 
LVL 4

Expert Comment

by:itamar
ID: 1350414
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
 
LVL 8

Author Comment

by:ZifNab
ID: 1350415
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
 
LVL 4

Expert Comment

by:itamar
ID: 1350416
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
 
LVL 4

Expert Comment

by:itamar
ID: 1350417
Still thinking on it...
0
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1350418
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
 
LVL 8

Author Comment

by:ZifNab
ID: 1350419
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
 
LVL 4

Expert Comment

by:itamar
ID: 1350420
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
 
LVL 8

Author Comment

by:ZifNab
ID: 1350421
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
 
LVL 4

Expert Comment

by:itamar
ID: 1350422
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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 8

Author Comment

by:ZifNab
ID: 1350423
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
 
LVL 8

Author Comment

by:ZifNab
ID: 1350424
How does Excel work with these different international settings?
0
 
LVL 8

Author Comment

by:ZifNab
ID: 1350425
Maybe I just save the Decimal and Date seperator to the Ini-file and then depending on that I do different readings.
0
 
LVL 4

Expert Comment

by:itamar
ID: 1350426
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
 
LVL 8

Author Comment

by:ZifNab
ID: 1350427
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
 
LVL 4

Expert Comment

by:itamar
ID: 1350428
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
 
LVL 8

Author Comment

by:ZifNab
ID: 1350429
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
 
LVL 4

Accepted Solution

by:
itamar earned 100 total points
ID: 1350430
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
 
LVL 8

Author Comment

by:ZifNab
ID: 1350431
Thanks itamar! I'll try to help you if you are having problems!
0
 
LVL 8

Author Comment

by:ZifNab
ID: 1350432
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
 
LVL 4

Expert Comment

by:itamar
ID: 1350433
It's an intelligent constant. It reflects the current settings in the machine you RUN the program.!
0
 
LVL 8

Author Comment

by:ZifNab
ID: 1350434
Thanks Itamar!
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This video discusses moving either the default database or any database to a new volume.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

744 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

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now