Delphi在字符串中改变Chars - 误解了行为 - XE3

时间:2014-03-11 00:05:54

标签: delphi

我正在某种编码器/解码器上做代码,现在已经超过2天无法弄清楚奇怪的行为......我希望有人可以理解并向我解释为什么会发生,无论它是什么是...

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

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数组,它使用随机字符顺序填充Enc[1 to 71].CharEnc[1 to 71].Enc[1 to 5];

代码是(或者至少应该是),以便它为每个第5行使用不同的编码列表(第1行enc[x].enc[1],第2行enc[x].enc[2],然后第5行{{ 1}},第6行返回enc[x].enc[5],依此类推......)

如果我从Memo1编码5行,那么:

enc[x].enc[1]

我得到一些随机单词,每个单词有5个字符,但是当解码它时,我会被返回

Memo1
Memo2
Memo3
Memo4
Memo5

(注意第3行中较低的m字母);

如果我再对此进行编码,我会得到与第一种情况完全相同的编码字符串列表,只有在这里,第3行的第3个字符! (wtf?)改变与第一个相同。 所以,对于Memo3,我得到Memo1 Memo2 memo3 Memo4 Memo5 ,而对于memo3,我得到q7M0e,这对我来说没有意义,因为char的位置应该是相同的,就我所知的代码而言。

这里有什么我想念的,在上面的代码中是明显的吗?

评论是否需要我粘贴完整表格(单位)的代码和exe示例,我会在网上给它并链接到...

编辑:

这是我正在编码/解码的“密钥”:http://txt.do/128b

2 个答案:

答案 0 :(得分:7)

您的方法存在一些问题。

一个问题是您使用String.Replace(),它将一个Char所有次出现替换为另一个Char。替换给定的Char后,您可能会在循环中使用不同的值替换相同的索引,从而在循环时丢弃数据。

另一个问题是你的解码逻辑。您允许使用5种不同的Char之一对每个未编码的Char进行编码。如果Char数组中Enc[1..71].Enc值的编码Encoder值与Enc[1..71].Char的相同值重复,则您将无法知道哪个Encoder用于解码。您的数组仅仅是随机数是不够的,但它们对于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;

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;

如果然后扩展阵列以允许所有可打印的ASCII字符,而不仅仅是其中的71个字符,那么代码会变得更简单:

// 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()简化为{{1}}使用的类似查找,而无需使用循环。我将把它作为练习留给你。

答案 1 :(得分:3)

假设我以字符串“abc”开头。

我想用“c”替换所有“a”,用“Q”替换所有“b”,并用“7”替换所有“c”。 也许我会写:

S := 'abc';
S := S . Replace ( 'a', 'c' );
S := S . Replace ( 'b', 'Q' );
S := S . Replace ( 'c', '7' );

结果是'7Q7'。哎呀!为什么不用“c”代替“a”? 嗯,确实如此。 在第一次调用Replace之后,S是'cbc'。 第二次通话后,S是'cQc'。 最后一次通话将'c'替换为'7'。

我想你在这里也做同样的事情。 除非我们看到你如何填充Enc结构,否则我无法给你角色代码字符的具体结果。