Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
494 Users Online NOW
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi



Loremo - the 1.5 liter car coming in 2009




Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (11)


String or Number? Undocumented Effects of Val(...)Format this article printer-friendly!Bookmark function is only available for registered users!
"Irregular" Hexadecimal Numbers
Product:
Delphi all versions
Category:
Object Pascal
Skill Level:
Scoring:
Last Update:
04/25/2005
Search Keys:
delphi delphi3000 article borland vcl code-snippet Val IntToStr InToStrDef Hexa hexadecimal decimal number string conversion
Times Scored:
6
Visits:
5311
Uploader: Daniel Wischnewski
Company: Delphi-PRAXiS
Reference: gate(n)etwork
 
Question/Problem/Abstract:
Recently I ran across an interesting phenomenon where an obvious string was converted into a number by Delphis Functions: Val, IntToStr and InToStrDef.
Answer:



Hi folks,

since quite some time I am using the following function to check whether a submitted string is a number or "just" a string with some non-numeric characters.

function IsInteger(const Str: String): Boolean;
var
  E, I: Integer;
begin
  Val(Str, I, E);
  Result := E = 0;
end;

It worked fine, or so it seemed, until the other day a rather rare situation occered.

The function returned True on the value of "x56e", which wasn't quite the thing I expected to happen. After a while of searching for the reason it became rather obvious. Delphi tries to interpret strings starting with either "0x", "x", or "$" as hexa-decimal numbers.

Well for strings starting with "$" I knew it would, in fact I wrote an articel about it, but the fact that "0x" and "x" are interpreted as well, was a newie for me.

Therefore "x56e" is equal to "0x56e", which is equal to "$056E" which is "Delphi"-hexadecimal to 1390 (decimal).

Anyway, I looked into the source code of the Val function, and here is the place where I found the solution:

@@endBlanks:
        MOV     CH,0
        CMP     BL,'-'
        JE      @@minus
        CMP     BL,'+'
        JE      @@plus
        CMP     BL,'$'
        JE      @@dollar

--->    CMP     BL, 'x'
        JE      @@dollar
--->    CMP     BL, 'X'
        JE      @@dollar
--->    CMP     BL, '0'
        JNE     @@firstDigit
        MOV     BL, [ESI]
        INC     ESI
--->    CMP     BL, 'x'
        JE      @@dollar
--->    CMP     BL, 'X'
        JE      @@dollar
        TEST    BL, BL
        JE      @@endDigits
        JMP     @@digLoop


The new version of my function converts the string to a number and back - if incoming string and resulting string are equal, it was a number, just the way I was it expecting to work.

function IsInteger(const Str: String): Boolean;
begin
  Result := IntToStr(StrToIntDef(Str, -1)) = Str;
end;

THANKS MAGNUS - THERE IS STILL A BUG IN THE PREVIOUS SOLUTION - SEE COMMENTS FOR A SOLUTION THAT ALMOST WORKS - you did forget about empty strings, though ;-)

Therefore, I will allow myself to add your solution to the article, slightly editied. Thanks again!

function IsInteger(Str: String) : boolean;
var
  I, L: Integer
begin
  Result := False;
  L := Length(Str);
  if L = 0 then
    // empty string
    Exit;
  if L > 1 then
    // first character for strings longer than one char
    if not (Str[1] in ['+', '-', '0'..'9']) then
      Exit
    else
  else
    // first character for strings exact one char long
    if not (Str[1] in ['0'..'9']) then
      Exit;  
  for I := 2 to length(Str) do
    // check remaining characters
    if not (Str[I] in ['0'..'9']) then
      Exit;
  Result := True;
end;


I hope, this will help you a little bit, once you are going to check for a numeric value.

By the way, no book I know of pays respect to this effect, a nice on it is, though ;-)

Content Ace





Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
Why not...
    Nick McCalip (Mar 21 2002 9:12PM)

Why not simply do the following:

function IsInteger(const value : string) : Boolean;
begin
  try
    IntToStr(value);
    Result := TRUE;
  except
    Result := FALSE;
  end;
end;
Respond

RE: Why not...
Nick McCalip (Mar 21 2002 9:14PM)

doh...

Replace IntToStr with StrToInt thus leaving...

function IsInteger(const value : string) : Boolean;
begin
  try
    StrToInt(value);
    Result := TRUE;
  except
    Result := FALSE;
  end;
end;

Respond

RE: Why not...
Daniel Wischnewski (Mar 22 2002 8:52AM)

I think you did not get the whole point of the Article. StrToInt will return 10 for XA, 0XA, $A, and for 10 itself. And I did not want StrToInt to check for hexa-decimal number, since the first two versions are undocumented!

So please, I wrote that StrToInt can be used for simple checking, however some undocumented side effects just simply had a bad effect in some of my applications.

And if you take a closer look at StrToInt, you will see, that it is essentially the same as the original version used, just slower. IntToStr call  Val internally and raises an additional exception if needed.
Respond

using the original idea
    Eber Irigoyen (Mar 7 2002 7:48AM)

...just testing for the ofending characters... here's your function:

function IsInteger(const Str: String): Boolean;
var
  E, I, Len: Integer;
begin
  Len:=Length(Str);
  If (Len>0) And (UpCase(Str[1])='X') Or (Str[1]='$') Then
    Result:=False
  Else If (Len>1) And (UpCase(Str[2])='X') Then
    Result:=False
  Else
  Begin

    Val(Str, I, E);
    Result := E = 0;
  End
end;


how's that?

salu2

keep up coding

EberSys
Respond

RE: using the original idea
Eber Irigoyen (Mar 7 2002 7:55AM)

...just make sure you call the function with the parameter "Str" with no spaces...as:
If (IsInteger(Trim(Edit1.Text))) Then
  dosomething;

or modify the function as:

function IsInteger(Str: String): Boolean;  //updated "Const" taken out
var
  E, I, Len: Integer;
begin
  Str:=Trim(Str); //updated function, added this line to remove spaces
  Len:=Length(Str);
  ...etc, etc, etc... rest of the function

salu2
EberSys
Respond

RE: using the original idea
Daniel Wischnewski (Mar 7 2002 8:39AM)

Spaces I do not want to check for, delibaretly, for. But yes, you can do it, anyway.

If you want to check for spaces, you should add the Trim, while calling the function, or add an additional (optional) parameter...
Respond

Another way to do it
    Magnus Flysjö (Mar 6 2002 10:52PM)

Another way to check if a string is a valid number is the following:

function NumericString(Str : String) : boolean;
var lp0 : integer
begin
result := true;
for lp0 := 1 to length(Str) do begin
  if (Ord(Str[lp0]) < $30) and (Ord(Str[lp0]) > $39) then begin
   result := false;
   break;
  end;
end;
end;

This function will not accept any other characters then 0..9, so if you want to add support for neg "-" or hex values "$" or "x" then you have to modify the code above to exclude these characters.

Respond

RE: Another way to do it
Daniel Wischnewski (Mar 6 2002 11:31PM)

Thanks, I've updated the article, added support for '+' and '-', as well checked for empty strings ;-)
Respond

???
    Luis Ortega (Mar 6 2002 9:22PM)

I have no test it,but... it will recognize '0123' as a number?
Respond

RE: ???
dan strandberg (Mar 6 2002 10:55PM)

No, '0123' will net return true.
Respond

RE: ???
Daniel Wischnewski (Mar 6 2002 11:22PM)

You are good - there is always a little something - anyway thank to Magnus - there is a solution that really should work.

However, I believe it is an interesting undocumented feature of Delphis power.
Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
M. Kleiner
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)