1

キーと値のペアを反復処理するために、ファイルから読み取った tdictionary に入力します。反復はDelphi 辞書反復で解決されました。

問題は、辞書の値が保持されないことです。おそらく、変数のスコープの問題です。私はJavaに慣れています...値は、プロシージャparsetextfileで辞書に割り当てた直後に存在し、その後失われます:

program parsefile;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, StrUtils, Dialogs, Generics.collections;

var key : string;
    dict: TDictionary<String, TStringlist>;
    KeysList, Valuename: TStringList;
    KeyName: string;
    i: integer;

function DeleteSpaces(str: string): string;
var
 i: Integer;
begin
 i:=0;
while i<=Length(str) do
  if str[i]=' ' then Delete(str, i, 1)
  else Inc(i);
  Result:=str;
end;

procedure HandleOneKey(KeyIndex:Integer; PrevKeys:string);
var L:TStringList;
    i:Integer;
    Part: string;
    KeyName: string;
begin
  KeyName := KeysList[KeyIndex];
  L := dict[KeyName];
  for i:=0 to L.Count-1 do
  begin
    writeln(L[i]);
    Part := KeyName + '=' + L[i];
    if KeyIndex = (KeysList.Count-1) then
      WriteLn(PrevKeys + ' ' + Part)
    else
      HandleOneKey(KeyIndex+1, PrevKeys + ' ' + Part);
  end;
end;

procedure Split(const Delimiter: Char;Input: string;const Strings: TStrings);
begin
   Strings.Clear;
   Strings.Delimiter := Delimiter;
   Strings.DelimitedText := Input;
end;

procedure parsetestfile;
  var testfile: Textfile;
      text: string;
      splitarray: TStringList;
      subsplit1, subsplit2: TStringList;
begin
  splitarray := TStringList.Create;
  subsplit1:= TStringList.Create;
  subsplit2:= TStringList.Create;
  AssignFile(testfile, 'g:\testfile.txt') ;
  Reset(testfile);

  while not Eof(testfile) do
  begin
    ReadLn(testfile, text);
    if AnsiContainsStr(text, '=') then
    begin
      Split('=', text, splitarray);
      splitarray[0] := trim(splitarray[0]);
      splitarray[1] := DeleteSpaces(splitarray[1]);
      if AnsiStartsStr('data', splitarray[0]) then
      begin
        split(' ', splitarray[0], subsplit1);
        splitarray[0]:=subsplit1[1];
        split(',', splitarray[1], subsplit2);
        dict.Add(splitarray[0], subsplit2);
        for ValueName in dict.Values do
        begin
          for i := 0 to Valuename.Count - 1 do
          write('Values are : '+ Valuename[i]);
        writeln;
        end;//for
      end;//end-data-check
    end;//end-=-check
  end;//while
  CloseFile(testfile);
  splitarray.Free;
  subsplit1.Free;
  subsplit2.Free;
end;

begin
  dict := TDictionary<String, TStringlist>.Create;
  parsetestfile;
  KeysList := TStringList.Create;

  for KeyName in dict.Keys do
    KeysList.Add(KeyName);
  for i := 0 to Keyslist.Count - 1 do
  begin
    writeln('Keylist Items: ' + Keyslist[i]);
  end;
  if KeysList.Count > 0 then
  begin
    HandleOneKey(0, '');
  end;
  dict.Destroy;
  Keyslist.Free;
  WriteLn('Press ENTER to make the window go away');
  ReadLn;
end.
4

1 に答える 1

2

トップ編集

私はあなたがJavaにもっと慣れているのを見ました、そのようなものがあなたの問題を説明します。Javaはガベージコレクターを使用します。何かへの参照がある場合、その1つが有効です。DelphiはGCを使用しません。割り当てたすべてのメモリを解放するのは、ユーザーの責任です。これは2番目の問題につながります。参照を保持しているメモリを解放できます。それを妨げるものは何もありません。手順では辞書にparsetestfile追加しているので、その参照のコピーを保持しています。subsplit2後で同じ手順で解放subsplit2するので、辞書にはDelphiが「空きメモリ」と見なすものへの参照が含まれるようになります。

Delphiを使用する場合は、ライフサイクル管理に非常に注意して慎重に取り組む必要があります。この場合subsplit2parsetestfileプロシージャ自体でを解放することはできませんが、後で解放する必要があります。を解放するときに解放する必要がありますDict。その方法については、私の最初のコードを参照してください。

*お勧め


これが多くのことを修正したコードです。コメントを読んでください、私は何かを変えたところはどこでもコメントを挿入しました。

コンパイルされ、値は解析手順に耐えますが、何を達成したいかわからず、サンプルテキストファイルを提供するのを忘れました。「1つ作成」する必要がありました。

program Project23;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, StrUtils, Dialogs, Generics.collections;

var deviceid, key, topmodule : string;
    dict: TDictionary<String, TStringlist>;
    KeysList: TStringList;
    KeyName: string;
    i: integer;

function DeleteSpaces(str: string): string;
var
 i: Integer;
begin
 i:=0;
while i<=Length(str) do
  if str[i]=' ' then Delete(str, i, 1)
  else Inc(i);
  Result:=str;
end;

procedure HandleOneKey(KeyIndex:Integer; PrevKeys:string);
var L:TStringList;
    i:Integer;
    Part: string;
    KeyName: string;
begin
  KeyName := KeysList[KeyIndex];
  L := dict[KeyName];
  for i:=0 to L.Count-1 do
  begin
    writeln(L[i]);
    Part := KeyName + '=' + L[i];
    if KeyIndex = (KeysList.Count-1) then
      WriteLn(PrevKeys + ' ' + Part)
    else
      HandleOneKey(KeyIndex+1, PrevKeys + ' ' + Part);
  end;
end;

procedure Split(const Delimiter: Char;Input: string;const Strings: TStrings);
begin
   Strings.Clear;
   Strings.Delimiter := Delimiter;
   Strings.DelimitedText := Input;
end;

procedure parsetestfile;
  var testfile: Textfile;
      text: string;
      splitarray: TStringList;
      subsplit1, subsplit2: TStringList;
      ValueName:TStringList; // Never Ever ignore compiler warnings!
      i: Integer; // Never Ever ignore compiler warnings!
begin
  splitarray := TStringList.Create;
  subsplit1:= TStringList.Create;      
  AssignFile(testfile, 'c:\temp\testfile.txt') ;
  Reset(testfile);

  while not Eof(testfile) do
  begin
    ReadLn(testfile, text);
    if AnsiContainsStr(text, '=') then
    begin
      Split('=', text, splitarray);
      splitarray[0] := trim(splitarray[0]);
      splitarray[1] := DeleteSpaces(splitarray[1]);
      if AnsiStartsStr('data', splitarray[0]) then
      begin

        subsplit2:= TStringList.Create; // Moved the creation of subsplit2 over here, because you need one fresh list for every line of text you read.

        split(' ', splitarray[0], subsplit1); // can't split on SPACE because the previous split allready broke the text at "=" and at SPACE. That's how DelimitedText works!
        // splitarray[0]:=subsplit1[1]; // splitarray[0] already contains the stuff before "="; And you should check the nubmer of lines in subsplit1!
        split(',', splitarray[1], subsplit2);
        dict.Add(splitarray[0], subsplit2);
        for ValueName in dict.Values do
        begin
          for i := 0 to Valuename.Count - 1 do
          writeLN('Values are : '+ Valuename[i]); // Only use Write when you intend to write the line terminator later
        writeln;
        end;//for
      end;//end-data-check
    end;//end-=-check
  end;//while
  CloseFile(testfile);
  splitarray.Free;
  subsplit1.Free;
  // subsplit2.Free; // Ooops! You're freeing Subsplit2, after you added it as a value in the dict.
end;

begin
  dict := TDictionary<String, TStringlist>.Create;
  parsetestfile;
  KeysList := TStringList.Create;

  for KeyName in dict.Keys do
    KeysList.Add(KeyName);
  for i := 0 to Keyslist.Count - 1 do
  begin
    writeln('Keylist Items: ' + Keyslist[i]);
  end;
  if KeysList.Count > 0 then
  begin
    HandleOneKey(0, '');
  end;
  dict.Free; // dict.Destroy; // never call "Destroy" directly, call .Free.
  Keyslist.Free;
  WriteLn('Press ENTER to make the window go away');
  ReadLn;
end.
于 2011-04-07T12:32:17.967 に答える