テキストファイルを読み込み、各行頭の値ごとに処理を行うには?

解決


maco  2004-03-23 05:19:05  No: 7876

各行の最初の一文字目に、識別用のフラグ文字が入ったテキストファイルを
読み込み、処理を行おうと思っています。

最終的な目標は、行頭のフラグを判別し、
フラグに合致した構造体に名前・項目1〜nを格納したいと考えています。

テキストファイルを読み込み、行頭のフラグを取り出すところで
つまずいてしまったので書き込みさせていただきました。

どなたか、アドバイス・関連リンク等の情報をお持ちでしたら、
教えて頂けないでしょうか?

宜しくお願い致します。

-------- テキストファイル例 --------

フラグ  名前  項目1  …  項目n
フラグ  名前  項目2  …  項目n
フラグ  名前  項目3  …  項目n
  :     :    :    …   :

(フラグ …「a」「z」などの文字)


にしの  2004-03-23 05:37:45  No: 7877

読み込みで詰まったのか、フラグの取り出しで詰まったのか解りませんが、とりあえず、「フラグの取り出し」ということで。

例えば、strという文字列型変数に1行が入っているとすれば、
case str[1] of
  'a': // フラグがaのとき
    ;
  'b': // フラグがbのとき
    ;
end;
とかけます。


tomo  2004-03-23 06:04:58  No: 7878

以下のコードでテキストファイルから各行の各項目のデータを文字列として取り出せます。ShowMessageの行を書き換えて構造体にデータをセットしてください。

var
        items, lines: TStrings;
        i, j: Integer;
begin
        lines := TStringList.Create;
        items := TStringList.Create;
        try
                lines.LoadFromFile('data.txt');
                for i := 0 to lines.Count-1 do
                begin
                        items.CommaText := lines[i];
                        for j := 0 to items.Count-1 do
                        begin
                                ShowMessage(Format('%d,%d=%s', [i, j, items[j]]));
                        end;
                end;
        finally
                lines.Free;
                items.Free;
        end;
end;


maco  2004-03-23 09:00:53  No: 7879

にしのさん、tomoさんありがとうございます。

私が詰まったのは、
「読み込んだデータからどうやって欲しいデータを取り出すか」です。
説明が不十分でごめんなさい。

外部ファイルからデータを読み込む際に、TMemoryStreamを使うとよいといった返信を良く見かけたのですが、
今回頂いたご回答では、TStringListで読み出しています。
こういった、読み込んだデータからほしいデータを抜き出す場合は、
TStringListの方が処理しやすいのでしょうか?


jok  2004-03-23 09:42:34  No: 7880

しめされたデータはテキストファイルでデータは1行ごとであり、空白区切り
であるように見えます。でしたら、TStringList で読みこみ、かく行のデータの
内容は tomo さんの示されたように、もう一つ TStringList をつかってその
CommaText で分離して処理します。これがもっとも普通のやり方だと思います。


にしの  2004-03-23 18:28:47  No: 7881

カンマ区切りでないなら、DelimitedTextのほうが適切かと。
空白をdelimiterに指定すれば出来そうです。
ただ、固定長の場合、recordを定義して、TMemoryStreamでreadしたほうが便利です。


maco  2004-03-23 19:00:16  No: 7882

jokさんありがとうございます。

今回の質問のような場合は、TStringListを使うのが一般的がよいということですね。

にしのさん、tomoさんのサンプルプログラムで先程動作を確認いたしました。
私がやりたかった処理が出来そうです。ありがとうございました。

このたびは皆さん、ありがとうございました。助かりました。


maco  2004-03-23 19:00:18  No: 7883

jokさんありがとうございます。

今回の質問のような場合は、TStringListを使うのが一般的がよいということですね。

にしのさん、tomoさんのサンプルプログラムで先程動作を確認いたしました。
私がやりたかった処理が出来そうです。ありがとうございました。

このたびは皆さん、ありがとうございました。助かりました。


maco  2004-03-23 19:11:33  No: 7884

にしのさん ありがとうございます。

>固定長の場合、recordを定義して、TMemoryStreamでreadしたほうが便利です。

テキストファイルは以下のように固定長になっています。(多少フラグで異なりますが…)
そういった場合は、TMemoryStreamでどのように読み込めばよいでしょうか?
もしよろしければ、教えて頂けないでしょうか?

-------------- テキストファイル例 --------------

フラグ(1)  名前(8)  項目1(8)  …  項目n(8)
    :

(補足)
  ・区切りは「半角スペース」
  ・括弧は最大バイト数、満たない場合は半角スペースを入れる
    (名前が「abc」ならば、「abc      」となる)


にしの  2004-03-23 19:44:26  No: 7885

例えばこんな感じです。
# エラーチェック・整合性などは見ていません

  TDataRec=record
    dummy0: char;
    sName: array[0..7] of char;
    dummy1: char;
    Item1: array[0..7] of char;
    dummy2: char;
    Item2: array[0..7] of char;
    dummy3: char;
    Item3: array[0..7] of char;
    dummy4: char;
  end;

と定義し、

procedure TForm1.Button1Click(Sender: TObject);
var
  fs: TFileStream;
  flag: char;
  dr: TDataRec;
begin
  fs := nil;
  try
    fs := TFileStream.Create('C:\test.txt', fmOpenRead);
    while fs.Read(flag, 1)=1 do
    begin
      case flag of
        'A': // 値は3つ
        begin
          fs.Read(dr, 1+8+1+8+1+8+1+8+2); // 最後の2はCRLF
          Memo1.Lines.Add('Name:[' + String(dr.sName) + ']');
          Memo1.Lines.Add('Item1:[' + String(dr.Item1) + ']');
          Memo1.Lines.Add('Item2:[' + String(dr.Item2) + ']');
          Memo1.Lines.Add('Item3:[' + String(dr.Item3) + ']');
        end;
        'B': // 値は2つ
        begin
          fs.Read(dr, 1+8+1+8+1+8+2); // 最後の2はCRLF
          Memo1.Lines.Add('Name:[' + String(dr.sName) + ']');
          Memo1.Lines.Add('Item1:[' + String(dr.Item1) + ']');
          Memo1.Lines.Add('Item2:[' + String(dr.Item2) + ']');
        end;
        else // 値は1つ
        begin
          fs.Read(dr, 1+8+1+8+2); // 最後の2はCRLF
          Memo1.Lines.Add('Name:[' + String(dr.sName) + ']');
          Memo1.Lines.Add('Item1:[' + String(dr.Item1) + ']');
        end;
      end;
    end;
  finally
    if Assigned(fs) then fs.Free;
  end;
end;

TMemoryStreamを使っていませんが、Readの使い方は同じです。
もっと良いやり方もあるかと思いますが、サンプルと言うことで。


maco  2004-03-23 23:43:32  No: 7886

にしのさん ご丁寧にありがとうございます。
この方法を改良しても同じ結果が得られそうです。

このサンプルをもとに、TFileStream・TMemoryStreamの勉強をしたいと思います。
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加