There are several problems with your approach.
One problem is with your use of String.Replace(), which replaces ALL occurrences of one Char with another Char. Once you replace a given Char, you can potentially replace that same index with a different value later on in your loops, thus trashing your data while you are looping.
Another problem is your decoding logic. You are allowing each un-encoded Char to be encoded with one of 5 different Chars. If those encoded Char values are duplicated at all across your Enc[1..71].Enc array for the same value of Encoder, you will not be able to know which Enc[1..71].Char to use for decoding. It is not enough that your arrays are simply random, but they also need to be unique for the same value of Encoder.
Also, your loops are redundant and overly complicated. They can be greatly simplified.
Try something more like this instead:
function TEncrypter.EncodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
for t := 1 to 71 do
begin
if Sign = Enc[t].Char then
begin
Result := Enc[t].Enc[Encoder];
Exit;
end;
end;
Result := Sign;
end;
function TEncrypter.DecodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
for t := 1 to 71 do
begin
if Sign = Enc[t].Enc[Encoder] then
begin
Result := Enc[t].Char;
Exit;
end;
end;
Result := Sign;
end;
procedure TEncrypter.Encode;
var
t, u, h: integer;
s: String;
begin
for h := 0 to EncodeBuffer.Count-1 do
begin
s := EncodeBuffer.Strings[h];
t := Length(s);
if t > 0 then
begin
for u := 0 to t-1 do
begin
s[u+1] := EncodeChar(s[u+1], (h mod 5) + 1);
end;
EncodeBuffer.Strings[h] := s;
end;
end;
end;
procedure TEncrypter.Decode;
var
t, u, h: integer;
s: String;
begin
for h := 0 to EncodeBuffer.Count-1 do
begin
s := EncodeBuffer.Strings[h];
t := Length(s);
if t > 0 then
begin
for u := 0 to t-1 do
begin
s[u+1] := DecodeChar(s[u+1], (h mod 5) + 1);
end;
EncodeBuffer.Strings[h] := s;
end;
end;
end;
// FormCreate
var
I, J, K, L: Integer;
Temp: Array[1..71] of Char;
NumInTemp: Integer;
begin
...
// initialize Enc[].Char as needed...
for I := 1 to 71 do
begin
Enc[I].Char := ...;
end;
// uniquely initialize each Enc[].Enc array for one value of Encoder...
for I := 1 to 5 do
begin
for J := 1 to 71 do
Temp[J] := ...; // must be unique for this iteration of I...
NumInTemp := 71;
// randomly assign Temp array to Enc[I].Enc array
for J := 1 to 71 do
begin
K := 1 + Random(NumInTemp);
Enc[J].Enc[I] := Temp[K];
for L := K+1 to NumInTemp do
Temp[L-1] := Temp[L];
Dec(NumInTemp);
end;
end;
...
end;
If you then expand your arrays to allow all printable ASCII characters, not just 71 of them, then the code gets a little simpler:
var
Enc : array [32..126] of Record
Char: Char;
Encr: string;
Enc: array [1..5] of Char;
end;
EncodeBuffer: TStringList;
function TEncrypter.EncodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
if (Sign >= #32) and (Sign <= #126) then
Result := Enc[Ord(Sign)].Enc[Encoder]
else
Result := Sign;
end;
function TEncrypter.DecodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
for t := Low(Enc) to High(Enc) do
begin
if Sign = Enc[t].Enc[Encoder] then
begin
Result := Enc[t].Char;
Exit;
end;
end;
Result := Sign;
end;
procedure TEncrypter.Encode;
var
u, h: integer;
s: String;
begin
for h := 0 to EncodeBuffer.Count-1 do
begin
s := EncodeBuffer.Strings[h];
for u := Low(s) to High(s) do
s[u] := EncodeChar(s[u], (h mod 5) + 1);
EncodeBuffer.Strings[h] := s;
end;
end;
procedure TEncrypter.Decode;
var
u, h: integer;
s: String;
begin
for h := 0 to EncodeBuffer.Count-1 do
begin
s := EncodeBuffer.Strings[h];
for u := Low(s) to High(s) do
s[u] := DecodeChar(s[u], (h mod 5) + 1);
EncodeBuffer.Strings[h] := s;
end;
end;
// FormCreate
var
I, J, K, L: Integer;
Temp: Array[32..126] of Char;
NumInTemp: Integer;
begin
...
for I := Low(Enc) to High(Enc) do
Enc[I].Char := Char(I);
for I := 1 to 5 do
begin
for J := Low(Temp) to High(Temp) do
Temp[J] := Char(J);
NumInTemp := Length(Temp);
for J := Low(Enc) to High(Enc) do
begin
K := Low(Temp) + Random(NumInTemp);
Enc[J].Enc[I] := Temp[K];
for L := K+1 to (Low(Temp)+NumInTemp) do
Temp[L-1] := Temp[L];
Dec(NumInTemp);
end;
end;
end;
And if you set up a separate decoder table instead of using Enc[].Enc, you can simplify TEncrypter.DecodeChar() to a similar lookup that TEncrypter.EncodeChar() uses, without having to use a loop at all. I will leave that as an exercise for you.
16
solved Delphi changing Chars in string – missunderstood behavior – XE3