how to use 2 functions at once in delphi? - delphi

OK, so here is what i mean since i couldnt think of a better title, I have 2 editbox's. 1 is for input of a string and the other is for the output.
ive been experimenting with edit2.text := LowerCase (edit1.text); & edit2.text := ReverseString (edit1.text);
i want to use the functions LowerCase & ReverseString at the same time so it both converts the capitals string to lowercase and reverses it also.. i just cant figure out how to do this without throwing all kinds of compiler errors, can anyone help me out

You should do
Edit2.Text := ReverseString(LowerCase(Edit1.Text));
Alternatively, since these functions commute, you can do
Edit2.Text := LowerCase(ReverseString(Edit1.Text));

How about edit2.text := LowerCase(ReverseString(edit1.text)) ?

Related

How to specify multiple ranges for an if statement in Delphi? [duplicate]

This question already has an answer here:
Delphi check if character is in range 'A'..'Z' and '0'..'9'
(1 answer)
Closed 5 years ago.
for counter := 1 to lengthofpassword do
begin
currentletter:=password[counter];
currentascii:=Ord(currentletter);
if (96<currentascii<123) OR (64<currentascii<91) OR (47<currentascii<58) then
Writeln('valid')
else
asciicheck:=false;
end;
I know this code is wrong but I did it to explain what I want to ask. How can you specify ranges for an if statement? Before, I messed around with lots of if statements and my code wasn't working the way I wanted it to. Basically, I am making a procedure which checks the user input for anything other than uppercase and lowercase alphabet and numbers. This question is different because I was looking for how this problem could be solved using a Case Of statement.
for counter := 1 to lengthofpassword do
begin
currentletter:=password[counter];
currentascii:=Ord(currentletter);
if (currentascii<48) AND (currentascii>57) then
asciipoints:=asciipoints+1;
if (currentascii<65) AND (currentascii>90) then
asciipoints:=asciipoints+1;
if (currentascii<97) AND (currentascii>122) then
asciipoints:=asciipoints+1;
Writeln(asciipoints);
end;
I also tried to do it like this but then realised this wouldn't work because if one statement was satisfied, the others wouldn't be and the points based system wouldn't work either.
Glad you found the answer yourself.
Another way to make sure the password only contains upper and lower case characters and numbers is what I tried to point to: define a set of characters that are valid and check if each character in your password is in these valid characters.
So with a set defined like this:
const
ValidChars = ['A'..'Z', 'a'..'z', '0'..'9'];
you can use statements like
if password[I] in ValidChars then
This statement will however generate a compiler warning in Unicode Delphi, as the type in a set is limited to 256 possible values, and their ordinalities must fall between 0 and 255. This isn't the case for WideChar with 65.536 values. So the set of char defined is in fact a set of AnsiChar. For this task this is acceptable, as every character that needs to be checked is ASCII, so using the function CharInSet will not generate a compiler warning and have a defined behavior - returning False - if the password contains Unicode characters.
This is the resulting code:
const
ValidChars = ['A'..'Z', 'a'..'z', '0'..'9'];
var
I: Integer;
begin
for I := 1 to passwordlength do
begin
if CharInSet(password[I], ValidChars) then
Writeln('valid') // more likely to do nothing and invert the if statement
else
begin
asciicheck := False;
Break; // No need to look further, the check failed
end;
end;
end;
Multiple ranges is best expressed in a case statement:
begin
for counter := 1 to lengthofpassword do
begin
case Ord(password[counter]) of
48..57,
65..90,
97..122 :
Writeln('valid')
else
asciicheck:=false;
end;
end;
end;
Now, this works for characters < #128. If you are working in a unicode application and don't want the restriction of characters being the english alphabet, it is possible to use TCharHelper.IsLetterOrDigit.
if password[counter].IsLetterOrDigit then ...
Thanks to a comment up above, I have found a solution. I ended up using a Case Of statement like this:
for counter := 1 to lengthofpassword do
begin
currentletter:=password[counter];
currentascii:=Ord(currentletter);
case currentascii of
97..122 : asciicheck:=true;
65..90 : asciicheck:=true;
48..57 : asciicheck:=true;
else asciicheck:=false;
end;
end;
Thanks once again.

Delphi - Checking length using pos

I'm using code from this article:
How to Convert Numbers (Currency) to Words
I can't seem to understand how the following code works exactly.
try
sIntValue := FormatFloat('#,###', trunc(abs(Number)));
sDecValue := Copy(FormatFloat('.#########', frac(abs(Number))), 2);
if (Pos('E', sIntValue) > 0) then // if number is too big
begin
Result := 'ERROR:';
exit;
end;
except
Result := 'ERROR:';
exit;
end;
How is it checking if the number is too big using the Pos() function? Why is it searching for E in an Integer? This make no sense to me. I would apprecaite any explanation (the code works just fine, I just want to understand why and how).
The code is checking for the use of scientific notation. That is where you write a number like 1000 as '1E3'.
The code is faintly ridiculous though. Hard to know why the author did not use the > comparison operator.

If statement for checking strings

So I'm trying to determine if two different strings are the same with
if DerobModel.ConstructionCount > 22 then
begin
for i := 22 to DerobModel.ConstructionCount-1 do
begin
ConstructionName[i] := DerobModel.Constructions[i].Name;
ShowMessage(ConstructionName[i]);
ShowMessage(DerobModel.HouseProperties.StringValue['NWall']);
if ConstructionName[i]=DerobModel.HouseProperties.StringValue['NWall'] then
begin
ShowMessage('Hej');
igSurf[0]:=idWallCon[i];
end;
LayerCount[i] := DerobModel.Constructions[i].LayerCount;
idWallCon[i] := i+1;
end;
end;
The ShowMessage for both of the strings returns the same string but somehow it won't go in the if statement. Any ideas?
The = operator for strings is known to work. When strings s1 and s2 are equal, s1 = s2 evaluates true. Otherwise it evaluates false. The = operator has been known to work correctly in all versions of Delphi.
The conclusion to draw is that if the body of your if does not execute, then the two strings are not equal. Now that you know that the two strings are not equal, you can debug the program to work out why two things that you believed to be equal are in fact not equal.
Note that equality testing with = is exact. Letter case is significant. Whitespace is significant. And so on.
Your strings are different, simple as that.
If you want to figure out what exactly is different, you could write an else block portion to compare the strings in detail and show you exactly what is different.
if ConstructionName[i]=DerobModel.HouseProperties.StringValue['NWall'] then
begin
ShowMessage('Hej');
igSurf[0]:=idWallCon[i];
end
else
begin
if (Length(ConstructionName[i]) <>
Length(DerobModel.HouseProperties.StringValue['NWall'])) then
begin
ShowMessage('Length('+IntToStr(Length(ConstructionName[i]))+') <> Length('+
IntToStr(Length(DerobModel.HouseProperties.StringValue['NWall']))+')');
end
else
begin
for LCharPos := 1 to Length(ConstructionName[i]) do
begin
if (ConstructionName[i][LCharPos] <>
DerobModel.HouseProperties.StringValue['NWall'][LCharPos]) then
begin
//Here you might need to rather show the ordinal values of the
//characters to see the difference if they **look** the same due
//to the font of the message.
ShowMessage('Pos['+IntToStr(LCharPos)+'] "'+
ConstructionName[i][LCharPos]+'" <> "'+
DerobModel.HouseProperties.StringValue['NWall'][LCharPos]+'"');
end;
end;
end;
end;
The only thing I can think of that might unexpectedly cause "same" strings to be reported as different is: if they are different string types. E.g. if one is WideString and the other AnsiString, then:
There would have to be an implicit conversion to do the comparison.
And this means one of the strings would be changed.
The change could cause two strings that look the same to actually be different.

Convert Array of ShortInt to String, Delphi

I'm doing the way I learned, that is:
with a FOR and taking the Index array one by one, but it is leaving too slow, would otherwise convert it to a String? that leaves quicker?
In my case it would be a Dynamic Array of ShortInt.
For example, given this input:
[0,20,-15]
I would like the following output:
0,20,-15
I suspect that your code is slow because it is performing unnecessary reallocations of the string. However, without seeing your code it's hard to be sure.
Probably the simplest way to code your algorithm is to use TStringBuilder. Whether or not that gives sufficient performance, only you can say.
sb := TStringBuilder.Create;
try
for i := 0 to high(buffer) do
begin
sb.Append(IntToStr(buffer[i]));
if i<high(buffer) then
sb.Append(',');
end;
str := sb.ToString;
finally
sb.Free;
end;

Any way to get TStringList.CommaText to not escape commas with quotes?

I'm doing some work with code generation, and one of the things I need to do is create a function call where one of the parameters is a function call, like so:
result := Func1(x, y, Func2(a, b, c));
TStringList.CommaText is very useful for generating the parameter lists, but when I traverse the tree to build the outer function call, what I end up with looks like this:
result := Func1(x, y, "Func2(a, b, c)");
It's quoting the third argument because it contains commas, and that produced invalid code. But I can't do something simplistic like StringReplace all double quotes with empty strings, because it's quite possible that a function argument could be a string with double quotes inside. Is there any way to make it just not escape the lines that contain commas?
You could set QuoteChar to be a space, and you'd merely get some extra spaces in the output, which is generally OK since generated code isn't usually expected to look pretty. String literals would be affected, though; they would have extra spaces inserted, changing the value of the string.
Free Pascal's TStrings class uses StrictDelimiter to control whether quoting occurs when reading the DelimitedText property. When it's true, quoting does not occur at all. Perhaps Delphi treats that property the same way.
Build an array of "unlikely characters" : non-keyable like †, ‡ or even non-printable like #129, #141, #143, #144.
Verify you don't have the 1st unlikely anywhere in your StringList.CommaText. Or move to the next unlikely until you get one not used in your StringList.CommaText. (Assert that you find one)
Use this unlikely char as the QuoteChar for your StringList
Get StringList.DelimitedText. You'll get the QuoteChar around the function parameters like: result := Func1(x, y, †Func2(a, b, c)†);
Replace the unlikely QuoteChar (here †) by empty strings...
What about using the Unicode version of AnsiExtractQuotedStr to remove the quotes?
Write your own method to export the contents of your TStringList to a string.
function MyStringListToString(const AStrings: TStrings): string;
var
i: Integer;
begin
Result := '';
if AStrings.Count = 0 then
Exit;
Result := AStrings[0];
for i := 1 to AStrings.Count - 1 do
Result := Result + ',' + AStrings[i];
end;
Too obvious? :-)
Alternatively, what would happen if you set StringList.QuoteChar to #0 and then called StringList.DelimitedText?
We have written a descendant class of TStringList in which reimplemented the DelimitedText property. You can copy most of the code from the original implementation.
var
LList: TStringList;
s, LOutput: string;
begin
LList := TStringList.Create;
try
LList.Add('x');
LList.Add('y');
LList.Add('Func2(a, b, c)');
for s in LList do
LOutput := LOutput + s + ', ';
SetLength(LOutput, Length(LOutput) - 2);
m1.AddLine('result := Func1(' + LOutput + ')');
finally
LList.Free;
end;
end;
Had the same problem, here's how I fixed it:
s := Trim(StringList.Text)
that's all ;-)

Resources