This is something that should be easey but I just can´t get it work.
I come from java so maby I have a error in my thinking here.
What I want to do is that I have a string with two letters like 't4' or 'pq'.
Now I just want to get each of the chracters in the string as an own string.
So I do:
firstString := myString[0];
but I don´t even get this compiled.
So I figured that they start counting form 1 and put 1 as an index.
Now I do this in a while loop and the first time I go through it it works fine. Then the second time the results are just empty or wrong numbers.
What am I missing here?
(I also tried copy but that doesn´t work either!)
while i < 10 do
begin
te := 'te';
a := te[1];
b := te[2];
i := i +1;
end;
the first loop a is 't' and b is 'e' as I would expect. The second time a is '' and b ist 't' which I don´t understand!
Strings are 1-based, not zero-based. Try the following, after adding StrUtils to your Uses list (for DupeString):
var
MyString : String;
begin
MyString := '12345';
Caption := StringOfChar(MyString[1], 8) + ':' + DupeString(Copy(MyString, 3, 2), 4);
You could split it up to mke it easier to follow, of course:
var
MyString,
S1,
S2,
S3: String;
begin
MyString := '12345';
S1 := StringOfChar(MyString[1], 8);
S2 := Copy(MyString, 3, 2);
S3 := DupeString(S2, 4);
Caption := S1 + ':' + S3;
Related
So I have 2 strings and I want to be able to say if the 2 strings are the same or not. The only problem is im filling the string 1 character by 1 using a while so if I use length/ord it doesn't work properly. I guess if you see the code im working with you will have an easier tas helping me out, so I'll just paste it here.
var
cad1, cad2: string;
car: char;
icad1, icad2: integer;
begin
car := 'o';
icad1 := 1;
icad2 := 1;
write('Write the cad1: ');
while (car<>'.') do begin
car := readkey;
cad1 := car;
write(car);
inc(icad1);
end;
car := 'o';
writeln;
write('Write thecad2: ');
while (car <> '.') do begin
car := readkey;
cad2 := car;
write(car);
inc(icad2);
end;
writeln;
end.
You have just to do :
CompareText(cad1, cad2)
it will return 0 if the two string are the same.
http://www.freepascal.org/docs-html/rtl/sysutils/comparetext.html
There are several problems in your code. For example: the line cad1:=car; assigns the character to a string. That means that the resulting string contains only one character equal to car. All the previous inputs are lost.
The simpliest way to input the strings and compare them is the following:
write('Write the cad1: ');
readln(cad1);
write('Write thecad2: ');
readln(cad2);
write(cad1=cad2);
readln;
The program has several "encryption" algorithms. This one should blockwise reverse the input. "He|ll|o " becomes "o |ll|He" (block length of 2).
I add two strings, in this case appending the result string to the current "block" string and making that the result. When I add the result first and then the block it works fine and gives me back the original string. But when i try to reverse the order it just gives me the the last "block".
Several other functions that are used for "rotation" are above.
//amount of blocks
function amBl(i1:integer;i2:integer):integer;
begin
if (i1 mod i2) <> 0 then result := (i1 div i2) else result := (i1 div i2) - 1;
end;
//calculation of block length
function calcBl(keyStr:string):integer;
var i:integer;
begin
result := 0;
for i := 1 to Length(keyStr) do
begin
result := (result + ord(keyStr[i])) mod 5;
result := result + 2;
end;
end;
//desperate try to add strings
function append(s1,s2:string):string;
begin
insert(s2,s1,Length(s1)+1);
result := s1;
end;
function rotation(inStr,keyStr:string):string;
var //array of chars -> string
block,temp:string;
//position in block variable
posB:integer;
//block length and block count variable
bl, bc:integer;
//null character as placeholder
n : ansiChar;
begin
//calculating block length 2..6
bl := calcBl(keyStr);
setLength(block,bl);
result := '';
temp := '';
{n := #00;}
for bc := 0 to amBl(Length(inStr),bl) do
begin
//filling block with chars starting from back of virtual block (in inStr)
for posB := 1 to bl do
begin
block[posB] := inStr[bc * bl + posB];
{if inStr[bc * bl + posB] = ' ' then block[posB] := n;}
end;
//adding the block in front of the existing result string
temp := result;
result := block + temp;
//result := append(block,temp);
//result := concat(block,temp);
end;
end;
(full code http://pastebin.com/6Uarerhk)
After all the loops "result" has the right value, but in the last step (between "result := block + temp" and the "end;" of the function) "block" replaces the content of "result" with itself completely, it doesn't add result at the end anymore.
And as you can see I even used a temp variable to try to work around that.. doesnt change anything though.
I am 99.99% certain that your problem is due to a subtle bug in your code. However, your deliberate efforts to hide the relevant code mean that we're really shooting in the dark. You haven't even been clear about where you're seeing the shortened Result: GUI Control/Debugger/Writeln
The irony is that you have all the information at your fingertips to provide a small concise demonstration of your problem - including sample input and expected output.
So without the relevant information, I can only guess; I do think I have a good hunch though.
Try the following code and see if you have a similar experience with S3:
S1 := 'a'#0;
S2 := 'bc';
S3 := S1 + S2;
The reason for my hunch is that #0 is a valid character in a string: but whenever that string needs to be processed as PChar, #0 will be interpreted as a string terminator. This could very well cause the "strange behaviour" you're seeing.
So it's quite probable that you have at least one of the following 2 bugs in your code:
You are always processing 1 too many characters; with the extra character being #0.
When your input string has an odd number of characters: your algorithm (which relies on pairs of characters) adds an extra character with value #0.
Edit
With the additional source code, my hunch is confirmed:
Suppose you have a 5 character string, and key that produces block length 2.
Your inner loop (for posB := 1 to bl do) will read beyond the length of inStr on the last iteration of the outer loop.
So if the next character in memory happens to be #0, you will be doing exactly as described above.
Additional problem. You have the following code:
//calculating block length 2..6
bl := calcBl(keyStr);
Your assumption in the comment is wrong. From the implementation of calcBl, if keyStr is empty, your result will be 0.
I have the text inside TEdit box:
'955-986, total = 32'
How would I delete all text after the comma, so it will only left '955-986'
I tried to limit the TEdit Length, but it's not working as I wanted it to be.
What if there'd be no comma? full non-cut string or empty string ?
Below is your idea of limiting string length, but only applied if at least one comma was found.
var
tmpStr:string;
commaPosition:integer;
begin
tmpStr := Edit1.Text;
commaPosition := pos(',',tmpStr);
if commaPosition > 0 then begin
SetLength(tmpStr, commaPosition - 1);
Edit1.Text := tmpStr;
end;
end;
You could use this code:
var
tmpStr:string;
commaPosition:integer;
begin
tmpStr := Edit1.Text;
commaPosition := pos(',',tmpStr);
tmpStr := copy(tmpStr,1,commaPosition-1);
Edit1.Text := tmpStr;
end;
I'm not a Delphi-Programmer (any more). However, I guess you get the String from the Text-Property of your TEdit-Box object, search for the first occurrence of , and get the index thereof and replace the Text contained in your TEdit-Box by the substring from the beginning of the current string to the found index.
edit.Text := Copy(edit.Text, 1, Pos(',', edit.Text)-1);
Sources:
http://docwiki.embarcadero.com/Libraries/en/System.Copy
http://docwiki.embarcadero.com/Libraries/en/System.Pos
TEdit.Text is a property and cannot be passed as var parameter. But once you introduce temporary variable, you can delegate checking of character index returned from Pos to Delete and it will handle all of cases.
var
S: string;
begin
S := Edit1.Text; // try '955-986, total = 32' and '955-986; total = 32'
Delete(S, Pos(',', S), MaxInt);
Edit1.Text := S;
end;
I have a list of strings and the values they are to be replaced with. I'm trying to combine them in a list like 'O'='0',' .'='.', ... so it's easy for me to edit it and add more pairs of replacements to make.
Right now the best way I could think of it is:
var
ListaLimpeza : TStringList;
begin
ListaLimpeza := TStringList.Create;
ListaLimpeza.Delimiter := '|';
ListaLimpeza.QuoteChar := '"';
ListaLimpeza.DelimitedText := 'O=0 | " .=."';
ShowMessage('1o Valor = '+ListaLimpeza.Names[1]+' e 2o Valor = '+ListaLimpeza.ValueFromIndex[1]);
This works, but it's not good for visuals, since I can't code the before string (for ex ' .') like that (which is very visual for the SPACE character), only like (" .) so that the = works to assign a name and value in the TStringList.
The Names and Values by default have to be separated by =, in the style of Windows INI files. There's no way AFAICT to change that separator. As #SirRufo indicates in the comment (and which I had never noticed), you can change that using the TStringList.NameValueSeparator property.
This will give you an idea of what Delphi thinks is in your TStringList, which is not what you think it is:
procedure TForm1.FormCreate(Sender: TObject);
var
SL: TStringList;
Temp: string;
i: Integer;
begin
SL := TStringList.Create;
SL.Delimiter := '|';
SL.QuoteChar := '"';
SL.StrictDelimiter := True;
SL.DelimitedText := 'O=0 | ! .!=!.!';
Temp := 'Count: ' + IntToStr(SL.Count) + #13;
for i := 0 to SL.Count - 1 do
Temp := Temp + Format('Name: %s Value: %s'#13,
[SL.Names[i], SL.ValueFromIndex[i]]);
ShowMessage(Temp);
end;
This produces this output:
TStringList Names/Values probably isn't going to do what you need. It's not clear what your actual goal is, but it appears that a simple text file with a simple list of text|replacement and plain parsing of that file would work, and you can easily use TStringList to read/write from that file, but I don't see any way to do the parsing easily except to do it yourself. You could use an array to store the pairs when you parse them:
type
TReplacePair = record
TextValue: string;
ReplaceValue: string;
end;
TReplacePairs = array of TReplacePair;
function GetReplacementPairs: TReplacePairs;
var
ConfigInfo: TStringList;
i, Split: Integer;
begin
ConfigInfo := TStringList.Create;
try
ConfigInfo.LoadFromFile('ReplacementPairs.txt');
SetLength(Result, ConfigInfo.Count);
for i := 0 to ConfigInfo.Count - 1 do
begin
Split := Pos('|`, ConfigInfo[i];
Result[i].TextValue := Copy(ConfigInfo[i], 1, Split - 1);
Result[i].ReplaceValue := Copy(ConfigInfo[i], Split + 1, MaxInt);
end;
finally
ConfigInfo.Free;
end;
end;
You can then populate whatever controls you need to edit/add/delete the replacement pairs, and just reverse the read operation to write them back out to save.
Lets say I have a String: Go to this page: http://mysite.com/?page=1 , and I have a string page. I would like to create a function like so:
MyBoolean := IsLink('Go to this page: http://mysite.com/?page=1','page',sLink);
// sLink is a Var, so it would return http://mysite.com/?page=1
Basically it is supposed to check if the word "page" is part of a link or not.
However I just can't figure it out. Any tips?
You could do something like
function GetLinkContaining(const Str, SubStr: string; out URL: string): boolean;
const
ValidURLSpecialChars = ['.', ':', '/', '?', '=', '&', '%'];
Prefixes: array[0..4] of string = ('http://', 'https://', 'ftp://', 'mailto:',
'www.');
function IsValidURLChar(const Char: char): boolean;
begin
result := IsLetterOrDigit(Char) or (Char in ValidURLSpecialChars);
end;
var
SubStrPos: integer;
Start, &End: integer;
i: Integer;
URLBegin: integer;
begin
result := false;
URLBegin := 0;
for i := low(Prefixes) to High(Prefixes) do
begin
URLBegin := Pos(Prefixes[i], Str);
if URLBegin > 0 then
break;
end;
if URLBegin = 0 then Exit(false);
SubStrPos := PosEx(SubStr, Str, URLBegin);
if SubStrPos = 0 then Exit(false);
Start := SubStrPos;
for i := SubStrPos - 1 downto 1 do
if IsValidURLChar(Str[i]) then
dec(Start)
else
break;
&End := SubStrPos + length(SubStr);
for i := SubStrPos + length(SubStr) to length(Str) do
if IsValidURLChar(Str[i]) then
inc(&End)
else
break;
URL := Copy(Str, Start, &End - Start);
result := true;
end;
To test it:
procedure TForm1.FormCreate(Sender: TObject);
var
s: string;
begin
if GetLinkContaining('Go to this page: http://mysite.com/?page=1 (right now!)',
'page', s) then
ShowMessage(s);
if GetLinkContaining('This is my favourite site (www.bbc.co.uk).', 'bbc', s) then
ShowMessage(s);
end;
To check if 'page' is part of a string you can use the function Pos.
function Pos(Str, Source : string): integer;
Pos returns an integer specifying the position of the first occurrence of one string within another.
Pos looks for the first complete occurence of Str in Source. If it finds one, it returns the character position in Source of the first character in Str as an integer value, otherwise it returns 0. Pos is case sensitive. So mybe you have to deal with upper- and lowe-case situations.
To extracrt the URL is (maybe) not so easy, you have to define more conditions. If the URL is always at the end of your string, you can copy everything from the http on (also use Pos and Copy!)
Among the more powerful string matching algorithms there are regular expressions. They allow for very complex matches without writing much code, although mastering them may require a little time. Latest versions of Delphi have already regular expression libraries, but you can find some for earlier versions as well.