• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 240
  • Last Modified:

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
0
ZifNab
Asked:
ZifNab
  • 11
  • 9
  • 3
1 Solution
 
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
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
 
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

Featured Post

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

  • 11
  • 9
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now