function HexToDec(Str: string): Integer;
var
i, M: Integer;
begin
Result:=0;
M:=1;
Str:=AnsiUpperCase(Str);
for i:=Length(Str) downto 1 do
begin
case Str[i] of
'1'..'9': Result:=Result+(Ord(Str[i])-Ord('0'))*M;
'A'..'F': Result:=Result+(Ord(Str[i])-Ord('A')+10)*M;
end;
M:=M shl 4;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if Edit1.Text<>'' then
Label2.Caption:=IntToStr(HexToDec(Edit1.Text));
end;
How to using it without function, because i want to call the result again in other line, and how about hexa to octal ? am i must conver from hexa to dec and then dec to octal?
Delphi can do this already, so you don't need to write a function parsing the number. It is quite simple, actually:
function HexToDec(const Str: string): Integer;
begin
if (Str <> '') and ((Str[1] = '-') or (Str[1] = '+')) then
Result := StrToInt(Str[1] + '$' + Copy(Str, 2, MaxInt))
else
Result := StrToInt('$' + Str);
end;
Note that that also handles negative hex numbers, or numbers like +$1234.
How to using it without function, because i want to call the result again in other line ?
If you want to re-use the value, assign the result of HexToDec to a variable and use that in IntToStr.
FWIW, in your function, there is no need to call AnsiUpperCase, because all hex digits fall in the ASCII range anyway. A much simpler UpperCase should work too.
My first comment would be that you are not converting hex to decimal with your function (although you are converting to decimal as an intermediate) but rather hex to integer. IntToStr then converts integer to base 10, effectively. To generalise what you want then I would create two functions - strBaseToInt and IntToStrBase where Base is meant to imply e.g. 16 for hex, 10 for dec, 8 for octal, etc., and assuming the convention adopted by hex that A=10, and so on but to (possibly) Z = 35 making the maximum base possible 36.
I don't handle + or - but that could be added easily.
In the reverse funtion, again for simplicity of illustration I have ommitted supporting negative values.
Edit
Thanks to Rudy for this improvement
Edit 2 - Overflow test added, as per comments
function StrBaseToInt(const Str: string; const Base : integer): Integer;
var
i, iVal, iTest: Longword;
begin
if (Base > 36) or (Base < 2) then raise Exception.Create('Invalid Base');
Result:=0;
iTest := 0;
for i:=1 to Length(Str) do
begin
case Str[i] of
'0'..'9': iVal := (Ord(Str[i])-Ord('0'));
'A'..'Z': iVal := (Ord(Str[i])-Ord('A')+10);
'a'..'z': iVal := (Ord(Str[i])-Ord('a')+10);
else raise Exception.Create( 'Illegal character found');
end;
if iVal < Base then
begin
Result:=Result * Base + iVal;
if Result < iTest then // overflow test!
begin
raise Exception.Create( 'Overflow occurred');
end
else
begin
iTest := Result;
end;
end
else
begin
raise Exception.Create( 'Illegal character found');
end;
end;
end;
Then, for example your HexToOct function would look like this
function HexToOct( Value : string ) : string;
begin
Result := IntToStrBase( StrBaseToInt( Value, 16), 8 );
end;
Additional
A general function would be
function BaseToBase( const Value : string; const FromBase, ToBase : integer ) : string;
begin
Result := IntToStrBase( StrBaseToInt( Value, FromBase ),ToBase );
end;
Related
How can I mark an integer into thousands and hundreds?
Just say I have an integer 12345678910, then I want to change it into a money value like 12.345.678.910.
I try the following code but it is not working.
procedure TForm1.Button1Click(Sender: TObject);
var
j,iPos,i, x, y : integer;
sTemp, original, hasil, data : string;
begin
original := edit1.Text;
sTemp := '';
j := length(edit1.Text);
i := 3;
while i < j do
begin
insert('.',original, (j-i));
edit1.Text := original;
j := length(edit1.Text);
for x := 1 to y do
begin
i := i + ( i + x );
end;
end;
edit2.Text := original;
There is System.SysUtils.Format call in Delphi http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.SysUtils.Format.
This call understand 'm' character as money specific formatter.
Try code like this:
Value := 12345678910;
FormattedStr := Format('Money = %m', [Value])
By default Format will use systemwide format settings, if you have to override default system settings, see official docs:
The conversion is controlled by the CurrencyString, CurrencyFormat,
NegCurrFormat, ThousandSeparator, DecimalSeparator, and
CurrencyDecimals global variables or their equivalent in a
TFormatSettings data structure. If the format string contains a
precision specifier, it overrides the value given by the
CurrencyDecimals global variable or its TFormatSettings equivalent.
This function does what you specify:
function FormatThousandsSeparators(Value: Int64): string;
var
Index: Integer;
begin
Result := IntToStr(Value);
Index := Length(Result) - 3;
while Index > 0 do
begin
Insert('.', Result, Index + 1);
Dec(Index, 3);
end;
end;
Note that your example 12345678910 does not fit into a 32 bit signed integer value which is why I used Int64.
This function does not handle negative values correctly. For instance, it returns '-.999' when passed -999. That can be dealt with like so:
function FormatThousandsSeparators(Value: Int64): string;
var
Index: Integer;
Negative: Boolean;
begin
Negative := Value < 0;
Result := IntToStr(Abs(Value));
Index := Length(Result) - 3;
while Index > 0 do
begin
Insert('.', Result, Index + 1);
Dec(Index, 3);
end;
if Negative then
Result := '-' + Result;
end;
i know now, its so simple. just use
showMessage(formatFloat('#.###.00', strToFloat(original)));
but thanks Remy, you opened my mind.
I want to convert a string of integers in hexadecimal (and the opposite).
I've seen the IntToHex functions, but it uses a small integer.
For example, I need to convert the number:
999888777666555444 in hexadecimal
and then the opposite:
hexadecimal number in 999888777666555444
If you need to convert more than 8-bytes values, you can represent your very-long-integer as array of byte, word, dword or something. In that case you should just convert any particular item and concatenate results. Opposite is the same (only thing you should remember is value should be considered as right-aligned).
converting a arbitrary length buffer to hex:
function HexDump(const _Buffer; _Len: integer): string;
type
PByte = ^Byte;
var
i: integer;
p: PByte;
begin
p := #_Buffer;
Result := '';
for i := 0 to _Len - 1 do begin
Result := Result + Long2Hex2(p^);
Inc(p);
end;
end;
And the utility functions used by this:
const
/// <summary>
/// String containing all characters that can be used as digits
/// </summary>
DIGIT_CHARS: string = '0123456789ABCDEFGHIJKlMNOPQRSTUVWXYZ';
function Long2Num(_l: ULong; _Base: Byte; _MinWidth: Integer = 1): string;
var
m: Byte;
begin
Result := '';
while _l > 0 do begin
m := _l mod _Base;
_l := _l div _Base;
Result := DIGIT_CHARS[m + 1] + Result;
end;
while Length(Result) < _MinWidth do
Result := '0' + Result;
end;
function Long2Hex(_l: ULong): string;
begin
Result := Long2Num(_l, 16);
end;
function Long2Hex2(_l: ULong): string;
begin
Result := Long2Hex(_l);
if Length(Result) < 2 then
Result := '0' + Result;
end;
These functions are part of my dzlib.
Note: This does not generate the hex numbers as you might expect them, e.g. if you pass an integer to the function like this:
var
IntValue: integer;
begin
IntValue := $12345678;
s := HexDump(IntValue, SizeOf(IntValue));
end;
You end up with s = '78563412' because Intel processors store integers in little endian format.
Unfortunately the other way round is more difficult, because there is no standard arbitrary length integer type in Delphi. There are some implementations of such a type though.
I am trying to validate a string, where by it can contain all alphebetical and numerical characters, aswell as the underline ( _ ) symbol.
This is what I tried so far:
var
S: string;
const
Allowed = ['A'..'Z', 'a'..'z', '0'..'9', '_'];
begin
S := 'This_is_my_string_0123456789';
if Length(S) > 0 then
begin
if (Pos(Allowed, S) > 0 then
ShowMessage('Ok')
else
ShowMessage('string contains invalid symbols');
end;
end;
In Lazarus this errors with:
Error: Incompatible type for arg no. 1: Got "Set Of Char", expected
"Variant"
Clearly my use of Pos is all wrong and I am not sure if my approach is even the correct way of going about it or not?
Thanks.
You will have to check every single character of the string, if it's contained in Allowed
e.g.:
var
S: string;
const
Allowed = ['A' .. 'Z', 'a' .. 'z', '0' .. '9', '_'];
Function Valid: Boolean;
var
i: Integer;
begin
Result := Length(s) > 0;
i := 1;
while Result and (i <= Length(S)) do
begin
Result := Result AND (S[i] in Allowed);
inc(i);
end;
if Length(s) = 0 then Result := true;
end;
begin
S := 'This_is_my_string_0123456789';
if Valid then
ShowMessage('Ok')
else
ShowMessage('string contains invalid symbols');
end;
TYPE TCharSet = SET OF CHAR;
FUNCTION ValidString(CONST S : STRING ; CONST ValidChars : TCharSet) : BOOLEAN;
VAR
I : Cardinal;
BEGIN
Result:=FALSE;
FOR I:=1 TO LENGTH(S) DO IF NOT (S[I] IN ValidChars) THEN EXIT;
Result:=TRUE
END;
If you are using a Unicode version of Delphi (as you seem to be), beware that a SET OF CHAR cannot contain all valid characters in the Unicode character set. Then perhaps this function will be useful instead:
FUNCTION ValidString(CONST S,ValidChars : STRING) : BOOLEAN;
VAR
I : Cardinal;
BEGIN
Result:=FALSE;
FOR I:=1 TO LENGTH(S) DO IF POS(S[I],ValidChars)=0 THEN EXIT;
Result:=TRUE
END;
but then again, not all characters (actually Codepoints) in Unicode can be expressed by a single character, and some characters can be expressed in more than one way (both as a single character and as a multi-character).
But as long as you constrain yourself within these limitations, one of the above functions should be useful. You can even include both, if you add an "OVERLOAD;" directive to the end of each function declaration, as in:
FUNCTION ValidString(CONST S : STRING ; CONST ValidChars : TCharSet) : BOOLEAN; OVERLOAD;
FUNCTION ValidString(CONST S,ValidChars : STRING) : BOOLEAN; OVERLOAD;
Lazarus/Free Pascal doesn't overload pos for that but has "posset" variants in unit strutils for that;
http://www.freepascal.org/docs-html/rtl/strutils/posset.html
Regarding Andreas' (IMHO correct ) remark, you can use isemptystr for that. It was meant to check for strings that only contain whitespace, but it basically checks if a string only contains characters in a set.
http://www.freepascal.org/docs-html/rtl/strutils/isemptystr.html
You can use Regular Expressions:
uses System.RegularExpressions;
if not TRegEx.IsMatch(S, '^[_a-zA-Z0-9]+$') then
ShowMessage('string contains invalid symbols');
Is there a method in Delphi to check if a string is a number without raising an exception?
its for int parsing.
and an exception will raise if one use the
try
StrToInt(s);
except
//exception handling
end;
function TryStrToInt(const S: string; out Value: Integer): Boolean;
TryStrToInt converts the string S, which represents an integer-type number in either decimal or hexadecimal notation, into a number, which is assigned to Value. If S does not represent a valid number, TryStrToInt returns false; otherwise TryStrToInt returns true.
To accept decimal but not hexadecimal values in the input string, you may use code like this:
function TryDecimalStrToInt( const S: string; out Value: Integer): Boolean;
begin
result := ( pos( '$', S ) = 0 ) and TryStrToInt( S, Value );
end;
var
s: String;
iValue, iCode: Integer;
...
val(s, iValue, iCode);
if iCode = 0 then
ShowMessage('s has a number')
else
ShowMessage('s has not a number');
Try this function StrToIntDef()
From help
Converts a string that represents an integer (decimal or hex notation) to a number with error default.
Pascal
function StrToIntDef(const S: string; Default: Integer): Integer;
Edit
Just now checked the source of TryStrToInt() function in Delphi 2007. If Delphi 7 dont have this function you can write like this. Its just a polished code to da-soft answer
function TryStrToInt(const S: string; out Value: Integer): Boolean;
var
E: Integer;
begin
Val(S, Value, E);
Result := E = 0;
end;
XE4 and newer:
for ch in s do
TCharacter.IsNumber(ch);
Don't forget:
uses System.Character
In delphi 7 you can use the Val procedure. From the help:
Unit: System
Delphi syntax: procedure Val(S; var V; var Code: Integer);
S is a string-type expression; it must be a sequence of characters that form a signed real number.
V is an integer-type or real-type variable. If V is an integer-type variable, S must form a whole number.
Code is a variable of type Integer.
If the string is invalid, the index of the offending character is stored in Code; otherwise, Code is set to zero. For a null-terminated string, the error position returned in Code is one larger than the actual zero-based index of the character in error.
use this function
function IsNumber(N : String) : Boolean;
var
I : Integer;
begin
Result := True;
if Trim(N) = '' then
Exit(False);
if (Length(Trim(N)) > 1) and (Trim(N)[1] = '0') then
Exit(False);
for I := 1 to Length(N) do
begin
if not (N[I] in ['0'..'9']) then
begin
Result := False;
Break;
end;
end;
end;
For older Delphi versions from delphi 5 help example:
uses Dialogs;
var
I, Code: Integer;
begin
{ Get text from TEdit control }
Val(Edit1.Text, I, Code);
{ Error during conversion to integer? }
if Code <> 0 then
MessageDlg('Error at position: ' + IntToStr(Code), mtWarning, [mbOk], 0);
else
Canvas.TextOut(10, 10, 'Value = ' + IntToStr(I));
end;
In some languages decimal separators are different (for example, '.' is used in English and ',' is used in Russian). For these cases to convert string to real number the following procedure is proposed:
function TryStrToFloatMultiLang(const S : String; out Value : Extended) : Boolean;
var
dc : char;
begin
Result := false;
dc := DecimalSeparator;
DecimalSeparator := '.';
try
Result := TryStrToFloat(S, Value);
except
DecimalSeparator := ',';
Result := TryStrToFloat(S, Value);
end;
DecimalSeparator := dc;
end;
Update
As #Pep mentioned TryStrToFloat catch exceptions, but it returns boolean value. So the correct code is:
function TryStrToFloatMultiLang(const S : String; out Value : Extended) : Boolean;
var
dc : char;
begin
Result := false;
dc := DecimalSeparator;
DecimalSeparator := '.';
Result := TryStrToFloat(S, Value);
if not Result then begin
DecimalSeparator := ',';
Result := TryStrToFloat(S, Value);
end;
DecimalSeparator := dc;
end;
When you using procedure
val(s, i, iCode);
and set value xd ....
val('xd', i, iCode)
as a result we obtain: 13
standard unit Variants
function VarIsNumeric(v:Variant):Boolean
What is the best way to convert a Delphi XE AnsiString containing escaped combining diacritical marks like "Fu\u0308rst" into a frienly WideString "Fürst"?
I am aware of the fact that this is not always possible for all combinations, but the common Latin blocks should be supported without building silly conversion tables on my own. I guess the solution can be found somewhere in the new Characters unit, but I don't get it.
I think you need to perform Unicode Normalization. on your string.
I don't know if there's a specific call in Delphi XE RTL to do this, but the WinAPI call NormalizeString should help you here, with mode NormalizationKC:
NormalizationKC
Unicode normalization form KC, compatibility composition. Transforms
each base plus combining characters to
the canonical precomposed equivalent
and all compatibility characters to
their equivalents. For example, the ligature fi becomes f + i; similarly, A + ¨ + fi + n becomes Ä + f + i + n.
Here is the complete code that solved my problem:
function Unescape(const s: AnsiString): string;
var
i: Integer;
j: Integer;
c: Integer;
begin
// Make result at least large enough. This prevents too many reallocs
SetLength(Result, Length(s));
i := 1;
j := 1;
while i <= Length(s) do begin
if s[i] = '\' then begin
if i < Length(s) then begin
// escaped backslash?
if s[i + 1] = '\' then begin
Result[j] := '\';
inc(i, 2);
end
// convert hex number to WideChar
else if (s[i + 1] = 'u') and (i + 1 + 4 <= Length(s))
and TryStrToInt('$' + string(Copy(s, i + 2, 4)), c) then begin
inc(i, 6);
Result[j] := WideChar(c);
end else begin
raise Exception.CreateFmt('Invalid code at position %d', [i]);
end;
end else begin
raise Exception.Create('Unexpected end of string');
end;
end else begin
Result[j] := WideChar(s[i]);
inc(i);
end;
inc(j);
end;
// Trim result in case we reserved too much space
SetLength(Result, j - 1);
end;
const
NormalizationC = 1;
function NormalizeString(NormForm: Integer; lpSrcString: LPCWSTR; cwSrcLength: Integer;
lpDstString: LPWSTR; cwDstLength: Integer): Integer; stdcall; external 'Normaliz.dll';
function Normalize(const s: string): string;
var
newLength: integer;
begin
// in NormalizationC mode the result string won't grow longer than the input string
SetLength(Result, Length(s));
newLength := NormalizeString(NormalizationC, PChar(s), Length(s), PChar(Result), Length(Result));
SetLength(Result, newLength);
end;
function UnescapeAndNormalize(const s: AnsiString): string;
begin
Result := Normalize(Unescape(s));
end;
Thank you all! I am sure that my first experience with StackOverflow won't be my last one :-)
Are they always escaped like this? Always in a number of 4 digits?
How is the \ character itself escaped?
Assuming the \character is escaped by \xxxx where xxxx is the code for the \ character, you can easily loop through the string:
function Unescape(s: AnsiString): WideString;
var
i: Integer;
j: Integer;
c: Integer;
begin
// Make result at least large enough. This prevents too many reallocs
SetLength(Result, Length(s));
i := 1; j := 1;
while i <= Length(s) do
begin
// If a '\' is found, typecast the following 4 digit integer to widechar
if s[i] = '\' then
begin
if (s[i+1] <> 'u') or not TryStrToInt(Copy(s, i+2, 4), c) then
raise Exception.CreateFmt('Invalid code at position %d', [i]);
Inc(i, 6);
Result[j] := WideChar(c);
end
else
begin
Result[j] := WideChar(s[i]);
Inc(i);
end;
Inc(j);
end;
// Trim result in case we reserved too much space
SetLength(Result, j-1);
end;
Use like this
MessageBoxW(0, PWideChar(Unescape('\u0252berhaupt')), nil, MB_OK);
This code is tested in Delphi 2007, but should work in XE as well due to the explicit use of Ansistring and Widestring.
[edit] Code is ok. Highlighter fails.
If I'm not mistaken, Delphi XE now supports regular expressions. I don't use them that often, though, but it seems a good way to parse the string and then replace all escaped values. Maybe someone has a good example of how to do this in Delphi with regular expressions?
GolezTrol,
you forget '$'
if (s[i+1] <> 'u') or not TryStrToInt('$'+Copy(s, i+2, 4), c) then