Mega Code Archive

 
Categories / Delphi / String
 

String or Number Undocumented Effects of Val(...)

Title: String or Number? Undocumented Effects of Val(...) Question: 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