1レコードが20のフィールドでできたテキストファイルがあります。区切りは複数のスペース、タブ、複数の改行が入り混じっています。これを見やすくグリッドに表示するにはどうすればいいのですか?
CSVならStringList.CommaTextで簡単にできるのですが・・
var
sl: TStringList;
iw: Word;
begin
sl := TStringList.Create;
try
sl.LoadFromFile('C:\aaa.txt');
for iw := 0 to Pred(sl.Count) do begin
StringGrid1.Rows[iw].CommaText := sl[iw];
end;
finally
sl.Free;
end;
end;
deldel様ありがとうございました。
1レコードの中に複数の改行が入っていますので、StringGridでは1レコードが複数行に表示されます。1レコードを1行に表示するには改行コードをスペースに置き換える処理が必要なのでしょうか?
あ〜改行があるんですか・・・(って、書いてましたね^^;)
そうですね、string変数に1レコード分のデータを格納し、あとは 、
S := StringReplace(S, #13, ',', [rfReplaceAll]);
でいいと思います。
StringListでは#13を読み込めそうもありませんので、墓場のように避けている(^^)TFileStreamあたりを勉強したいと思います。初歩的な質問にもかかわらず、お付き合い下さいましたdeldel様に無限の感謝を捧げます。
編集 削除>>1レコードが20のフィールドでできたテキストファイル
20フィールド固定なら、レコードを無視して単純に20個読んだら
StringGrid.row + 1 すればよいのでは?
そんな単純な事ではないかなー?
あと、テキストファイルなのに1レコードに改行があるというのは、
どんな形なのでしょうか?なんかピンと来ないのですが、きっと
3Kさんのようにすればいいような気がします。
deldelさんの仰るとおり、データの一部を見せてもらえたら、また違った回答もつくのではないでしょうか?
危ないトコは、適当にマスクかけておけばよろしいかと。
ちなみに、ここで私が最後にレスしたTStringListExなんぞは、使えないか?
https://www.petitmonte.com/bbs/answers?question_id=2891
もっとも、ダブルクォーテションで囲まれていないデータの改行は、無視されますがね。
多くの方々の手を煩わせて恐縮しております(m m)
MSDE2000で
osql -U sa -d Mydatabase -q "DBCC SHOWCONTIG WITH TABLERESULTS,ALL_INDEXES"
-o "c:\Showcontig.txt"
のようにDBCC SHOWCONTIG を -oスイッチをつけて実行して得たtxtファイルです。
2レコード分がこれです↓
-------------------------------
sysobjects
1
ncsysobjects2
3
0 1 196 9
9 9.0 0
1 0 5352.0
33.876945495605469 100.0 1
1 0.0 0.0
sysindexes
2
sysindexes
1
0 12 319 110
458 205.22800000000001 0
7 9 2563.8330078125
68.32427978515625 20.0 2
10 41.666667938232422 42.857143402099609
--------------------------------
sl := TStringList.Create;
sl.LoadFromFile('c:\showcontig.txt');
showmessage('count='+inttostr(sl.Count));
を実行しますとcount=18を表示します。18・・・・?
StringListで読み込むこと自体に無理があります?
行の途中にはレコードの区切りがないのですね。そして、各フィールドは半角文字だけで出来ていると。
その場合は、TStringList でファイルを読み込んで処理するのは簡単です。
ここでは、TStringList で読み込むかわりに Memo1 に上のデータをコピペしました。
Memo1.Lines と TStringList は同型ですから同じように処理できます。
あらかじめ StringGrid1 を Form1 に貼り付けて置いてください。
procedure TForm1.FormCreate(Sender: TObject);
begin
with StringGrid1 do
begin
FixedCols := 0;
FixedRows := 0;
RowCount := 1;
ColCount := 20;
end;
end;
procedure ExtractData(const str: string; sl:TStringList);
const
Delim: set of Char = [' ', #9];
var
i, start: integer;
state: Boolean;
begin
state := false;
for i := 1 to length(str) do
begin
if (str[i] in Delim) then
begin
if state then
begin
sl.Add(Copy(str,start,i-start));
state := false;
end;
end
else
begin
if not state then
begin
start := i;
state := true;
end;
end;
end;
if state then
sl.Add(Copy(str,start,Length(str)));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
sl: TStringList;
i: integer;
begin
sl := TStringList.Create;
try
for i := 0 to Memo1.Lines.Count-1 do
begin
ExtractData(Memo1.Lines[i], sl);
if sl.Count = 20 then
begin
StringGrid1.RowCount := StringGrid1.RowCount +1;
StringGrid1.Rows[StringGrid1.RowCount-1].Assign(sl);
sl.Clear;
end;
end;
finally
sl.Free;
end;
end;
こんな感じでうまくいきました。
procedure TForm1.Button1Click(Sender: TObject);
const
BYTES_PER_REC = 632;
var
f: File;
buf: array[1..BYTES_PER_REC] of Char;
i: Integer;
begin
AssignFile(f,'C:\Showcontig.txt');
Reset(f,1);
//
i := 0;
while not EOF(f) do begin
BlockRead(f,buf,SizeOf(buf));
StringGrid1.Rows[i].CommaText := buf;
Inc(i);
end;
//
CloseFile(f);
//
StringGrid1.RowCount := i;
end;
とか
procedure TForm1.Button2Click(Sender: TObject);
const
LINES_PER_REC = 9;
var
sl: TStringList;
s: string;
recCnt,i,j,k: Integer;
begin
sl := TStringList.Create;
sl.LoadFromFile('C:\Showcontig.txt');
//
recCnt := sl.Count div LINES_PER_REC;
for i:=0 to recCnt-1 do begin
s := '';
k := i*LINES_PER_REC;
for j:=k to k+(LINES_PER_REC-1) do
s := s+sl[j];
StringGrid1.Rows[i].CommaText := s;
end;
//
sl.Free;
//
StringGrid1.RowCount := recCnt;
end;
では、ダメっすかね?
>墓場のように避けている(^^)TFileStreamあたりを...
procedure TForm1.Button1Click(Sender: TObject);
var
ms: TMemoryStream;
pS, pD, pT: PChar;
iCol, iRow: Integer;
dCord: Boolean;
begin
ms := TMemoryStream.Create;
ms.LoadFromFile('__src.txt'); // 元のDATAファイル(20フィールド、複数レコード)
pS := ms.Memory;
pS[ms.Size] := #0;
dCord := True;
iCol := 0;
iRow := 0;
pD := pS;
pT := pD;
while pS^ <> #0 do begin
if pS^ in [#9,#10,#13,#32] then begin
if not dCord then begin
pD^ := ',';
inc(pD);
inc(iCol);
end;
dCord := True;
end else begin
pD^ := pS^;
inc(pD);
dCord := False;
end;
inc(pS);
// 1レコード分をStringGridにセット
if iCol >= 20 then begin
if (pD-1)^ = ',' then dec(pD);
pD^ := #0;
inc(iRow);
StringGrid1.ColCount := 21;
StringGrid1.RowCount := iRow + 1;
StringGrid1.Rows[iRow].CommaText := 'レコード,'+ pT;
pD^ := #13; inc(pD);
pD^ := #10; inc(pD);
pT := pD;
iCol := 0;
end;
end;
pD^ := #0;
ms.Size := pD - ms.Memory;
ms.SaveToFile('__dst.txt'); // CSV変換ファイル
Memo1.SetTextBuf(ms.Memory);
ms.Free;
end;
count=18は行数を返していたのでした・・・(^^;)
anone様、通りすがり様数々の着眼点を簡明なコードで提示して頂きまして有難うございました。シックリと理解できました事をご報告いたします。
deldel様、3K様、ん?様適切な助言と味わい深いsuggestionを有難うございました。
Streamを嫌うと・・様、御教示くださいましたコードは諸般の事情(?)により、未だ理解の及ばない部分を含みますが、今後の課題を頂いたものと感謝いたします。
多くの方々の暖かいご指導に対して、深く御礼申し上げます。
1レコードが9行ならば、以下でもできました。
var
sl1, sl2: TStringList;
ib: Byte;
sa: AnsiString;
iwRowCount: Word;
begin
sl1 := TStringList.Create;
sl2 := TStringList.Create;
try
sl1.LoadFromFile('c:\showcontig.txt');
iwRowCount := 0;
while True do begin
if sl1.Count < 9 then Break;
sl2.Clear;
for ib :=1 to 9 do begin
sl2.Add(sl1[0]);
sl1.Delete(0);
end;
sa := StringReplace(sl2.Text, #13#10, ',', [rfReplaceAll]);
StringGrid1.Rows[iwRowCount].CommaText := sa;
inc(iwRowCount);
end;
finally
sl1.Free;
sl2.Free;
end;
end;
ちなみに、改行コードが入ってるだけで、実質固定長なんじゃ・・・?
編集 削除はじめから固定長ですけど
編集 削除>はじめから固定長ですけど
どこに「固定長」と書いてあったんでしょう?
>のようにDBCC SHOWCONTIG を -oスイッチをつけて実行して得たtxtファイルです。
もしかして、これが「固定長」と判断するもの?
ちなみに、固定長なら1レコード分読み込んで、CopyやTrim関数とか使って地道に切り崩すだけでよかったと思うのだが。。。
しかも「1レコードが9行」と決まっているような感じだし。