德尔福改变字符串中的字符串 - 错误的行为 - XE3 [英] Delphi changing Chars in string - missunderstood behavior - XE3

查看:327
本文介绍了德尔福改变字符串中的字符串 - 错误的行为 - XE3的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在编码/解码器上编写代码,现在看不出奇怪的行为超过2天...我希望有人能够理解和解释为什么会发生,无论如何是...

I'm doing a code on some kind of encoder/decoder, and can't figure out the strange behavior for more than 2 days now... I hope someone might understand and explain to me why is happening, whatever it is...

这是主要代码,它是做什么的(我删除了表单的信息,按钮等,只是核心,以避免垃圾)

Here's the main code, which does the thing (I removed the form's info, buttons etc, just the core to avoid garbage)

unit Encoder;
//
interface
//

var
  Enc : array [1..71] of Record
    Char: Char;
    Encr: string;
    Enc: array [1..5] of Char;
  end;
  EncodeBuffer: TStringList;

implementation

{$R *.dfm}

procedure TEncrypter.Encode;
var
  s, t, u, h, h2, h3, h4, h5: integer;
begin
  s := EncodeBuffer.Count;
  h := 0;
  h2 := 1;
  h3 := 2;
  h4 := 3;
  h5 := 4;

  while h < s do
  begin
    t := EncodeBuffer.Strings[h].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h] := EncodeBuffer.Strings[h].Replace(EncodeBuffer.Strings[h].Chars[u], EncodeChar(EncodeBuffer.Strings[h].Chars[u], 1));
      end;
    end;
    h := h + 5;
  end;

  while h2 < s do
  begin
    t := EncodeBuffer.Strings[h2].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h2] := EncodeBuffer.Strings[h2].Replace(EncodeBuffer.Strings[h2].Chars[u], EncodeChar(EncodeBuffer.Strings[h2].Chars[u], 2));
      end;
    end;
    h2 := h2 + 5;
  end;

  while h3 < s do
  begin
    t := EncodeBuffer.Strings[h3].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h3] := EncodeBuffer.Strings[h3].Replace(EncodeBuffer.Strings[h3].Chars[u], EncodeChar(EncodeBuffer.Strings[h3].Chars[u], 3));
      end;
    end;
    h3 := h3 + 5;
  end;

  while h4 < s do
  begin
    t := EncodeBuffer.Strings[h4].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h4] := EncodeBuffer.Strings[h4].Replace(EncodeBuffer.Strings[h4].Chars[u], EncodeChar(EncodeBuffer.Strings[h4].Chars[u], 4));
      end;
    end;
    h4 := h4 + 5;
  end;

  while h5 < s do
  begin
    t := EncodeBuffer.Strings[h5].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h5] := EncodeBuffer.Strings[h5].Replace(EncodeBuffer.Strings[h5].Chars[u], EncodeChar(EncodeBuffer.Strings[h5].Chars[u], 5));
      end;
    end;
    h5 := h5 + 5;
  end;
end;

procedure TEncrypter.Decode;
var
  s, t, u, h, h2, h3, h4, h5: integer;
begin
  s := EncodeBuffer.Count;
  h := 0;
  h2 := 1;
  h3 := 2;
  h4 := 3;
  h5 := 4;

  while h < s do
  begin
    t := EncodeBuffer.Strings[h].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h] := EncodeBuffer.Strings[h].Replace(EncodeBuffer.Strings[h].Chars[u], DecodeChar(EncodeBuffer.Strings[h].Chars[u], 1));
      end;
    end;
    h := h + 5;
  end;

  while h2 < s do
  begin
    t := EncodeBuffer.Strings[h2].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h2] := EncodeBuffer.Strings[h2].Replace(EncodeBuffer.Strings[h2].Chars[u], DecodeChar(EncodeBuffer.Strings[h2].Chars[u], 2));
      end;
    end;
    h2 := h2 + 5;
  end;

  while h3 < s do
  begin
    t := EncodeBuffer.Strings[h3].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h3] := EncodeBuffer.Strings[h3].Replace(EncodeBuffer.Strings[h3].Chars[u], DecodeChar(EncodeBuffer.Strings[h3].Chars[u], 3));
      end;
    end;
    h3 := h3 + 5;
  end;

  while h4 < s do
  begin
    t := EncodeBuffer.Strings[h4].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h4] := EncodeBuffer.Strings[h4].Replace(EncodeBuffer.Strings[h4].Chars[u], DecodeChar(EncodeBuffer.Strings[h4].Chars[u], 4));
      end;
    end;
    h4 := h4 + 5;
  end;

  while h5 < s do
  begin
    t := EncodeBuffer.Strings[h5].Length;
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        EncodeBuffer.Strings[h5] := EncodeBuffer.Strings[h5].Replace(EncodeBuffer.Strings[h5].Chars[u], DecodeChar(EncodeBuffer.Strings[h5].Chars[u], 5));
      end;
    end;
    h5 := h5 + 5;
  end;
end;

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];
      Break;
    end
    else
      Result := Sign;
  end;
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;
      Break;
    end
    else
      Result := Sign;
  end;
end;

我有一个在 FormCreate 事件,填写 Enc [1〜71] .Char Enc [1〜71] .Enc [1〜5] 带有随机字符顺序;

I have an Enc array created on FormCreate event, which fills Enc[1 to 71].Char and Enc[1 to 71].Enc[1 to 5] with random char order;

代码(或至少应该是)使得它对于每个第5行使用不同的数组列表(行1 enc [x] .enc [1] ,第2行 enc [x] .enc [2] ,然后行5 enc [x] .enc [5] ,第6行返回 enc [x] .enc [1] 等等...)

The code is made (or at least should be) so that it uses different encode list from array for each 5th line (line 1 enc[x].enc[1], line 2 enc[x].enc[2], and then line 5 enc[x].enc[5], and line 6 back to enc[x].enc[1] and so on...)

如果我从Memo1编码5行,它们是:

If I encode 5 lines from Memo1, which are:

Memo1
Memo2
Memo3
Memo4
Memo5

我收到一些随机的字,每个都有5个字符,但是当它解码时,我会返回

I get some random words with 5 chars each, however when decoding it back, I get returned

Memo1
Memo2
memo3
Memo4
Memo5 

(注意第三行中的下半部分字母);

(notice the lower m letter in 3rd line);

如果我再次对其进行编码,我将获得完全相同的编码条纹nglist在第一种情况下,只有这里,第3行的第3个字符! (wtf?)与第一个相同。
所以,对于Memo3,我得到 q7M0e ,对于memo3,我得到 q7q0e ,这是没有意义的我,因为一个字符的位置应该是一样的,只要我明白的代码。

If I then encode this again, I get the exact same encoded stringlist as in the first case, only that here, the 3rd line's 3rd char! (wtf?) is changed with the same as the firstone is. so, for Memo3 I get q7M0e, and for memo3 I get q7q0e, which makes no sense to me, as the position of a char should be the same, as far as I understand by the code.

有什么我在这里缺少,值得注意的代码以上??

Is there anything I'm missing here, noticable in the code above??

评论如果我需要粘贴完整的表单(单位)的代码和exe示例,我会给它一个网站链接到...

Comment if there's a need for me to paste the complete form's (unit's) code and exe example, I'll give it on a web and link to that...

编辑:

这里是我的编码/解码的键 http://txt.do/128b

Here's the "key", by which I'm encoding/decoding: http://txt.do/128b

推荐答案

您的方法有几个问题。

一个问题是使用 String.Replace() ,用 Char 全部一个 Char >。一旦您替换了一个给定的 Char ,您可以在循环中替换相同的索引,然后在循环中替换不同的值,从而在循环时丢弃数据。

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.

另一个问题是您的解码逻辑。您允许使用5种不同的 Char 之一编码每个未编码的 Char 。如果编码为 Char 的值在您的 Enc [1..71] .Enc 数组之间重复相同值 Encoder ,您将无法知道哪些 Enc [1..71] .Char 用于解码。您的数组是简单的随机的还不够,但是对于相同的值 Encoder ,它们也需要是唯一的。

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;

如果然后将数组扩展为允许所有可打印的ASCII字符,而不仅仅是其中的71个字符,那么代码有点简单:

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;

如果您设置了单独的解码器表,而不是使用 Enc [] .Enc ,您可以将 TEncrypter.DecodeChar()简化为类似的查找 TEncrypter.EncodeChar()使用,而不必使用循环。我会把它作为一个练习。

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.

这篇关于德尔福改变字符串中的字符串 - 错误的行为 - XE3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆