FILE1.TXTの内容
A B C D E F
①ax 101abc x10 x20 y10 y20
②ax 235abc x11 x21 y11 y21
③ax 098acd x12 x22 y12 y22
④ax 125bac x13 x23 y13 y23
⑤ax 215abc x14 x24 y14 y24
⑥ax 487abj x15 x25 y15 y25
⑦ax 894akc x16 x26 y16 y26
⑧ax 236bcg x17 x27 y17 y27
;
;
EOF
FILE2.TXTの内容
A B C D E F
③ax 098acd x12 x22 y12 y22
①ax 101abc x10 x20 y10 y20
④ax 125bac x13 x23 y13 y23
⑤ax 215abc x14 x24 y14 y24
②ax 235abc x11 x21 y11 y21
⑧ax 236bcg x17 x27 y17 y27
⑥ax 487abj x15 x25 y15 y25
⑦ax 894akc x16 x26 y16 y26
;
;
EOF
FILE1.TXTの内容を初めからEOFまで1行づつ読み込んで
Bの文字列を基準にしてファイル内の各行をソートし、
新規ファイルFILE2.TXTへ書き込んで終了するコードを教えてさい。
できればオーソドックスな方法とTStringClassを使った方法の
2通りでお願い致します。
①とかはわかりやすくするために表示してあるだけですよね?
だとしたらソートすればいいと思いますけど
var
str:TStringList;
begin
str:=TStringList.Create;
str.LoadFromFile('FILE1.TXT');
str.Sort;
str.SaveToFile('FILE2.TXT');
str.Free;
end;
こういうことじゃないですか?
間違ってたらすみません。
申し訳ないです。
以下のファイル内容の間違いでした。
おっしゃる通り①とはファイル内に無いです。
Classを使わないコードとClassを使うコードを
ソートを理解したいので改めて教えて頂けないでしょうか?
FILE1.TXTの内容
A B C D E F
①fx 101abc x10 x20 y10 y20
②cx 235abc x11 x21 y11 y21
③ax 098acd x12 x22 y12 y22
④bx 125bac x13 x23 y13 y23
⑤ax 215abc x14 x24 y14 y24
⑥ax 487abj x15 x25 y15 y25
⑦dx 894akc x16 x26 y16 y26
⑧ax 236bcg x17 x27 y17 y27
;
;
EOF
FILE2.TXTの内容
A B C D E F
③ax 098acd x12 x22 y12 y22
①fx 101abc x10 x20 y10 y20
④bx 125bac x13 x23 y13 y23
⑤ax 215abc x14 x24 y14 y24
②cx 235abc x11 x21 y11 y21
⑧ax 236bcg x17 x27 y17 y27
⑥ax 487abj x15 x25 y15 y25
⑦dx 894akc x16 x26 y16 y26
;
;
EOF
TStringList の CustomSort を使えば、簡単にできすます。
function MySort(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := CompareStr(Copy(List[Index1], 5, 6), Copy(List[Index2], 5, 6));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
str:TStringList;
begin
str:=TStringList.Create;
str.LoadFromFile('FILE1.TXT');
str.CustomSort(MySort);
str.SaveToFile('FILE2.TXT');
str.Free;
end;
1行目の
A B C D E F
や、最後の、
EOF
という行があるのなら先に削除してからソートしてください。
>Classを使わないコード
とは、TList、TFileStream 等のクラスも使わないでということですか。
TStringList の CustomSortはいろいろ調べたんですが、便利なものがDelphiには、用意されているんですね。
Classを使わないコードとは、標準入出力やソート部を自分で作成する事です。
TStringList を使わないとすると、固定長データなので、
1行をRecord型の変数に格納するのが常套手段でしょう。
全体のデータの格納先としては、TList か 動的配列 か、になります。
TList は、Sortメソッドを持ってますので、ソートは楽ですが、
ポインタとして扱わなければならないので、インスタンスを作成したり、
解放したりしなければなりません。
どちらも一長一短ですが、
今回のリクエストはソート部は自分でということなので、
動的配列を使ってみました。
標準入出力で、とういうことでしたが、TFileStream にしました。
操作としてはほとんど同じですか、標準入出力では、排他制御が
できませんので、安全性を考慮して TFileStream にしました。
ソートはクイックソートを使いました。TListやTStringListと
同じ手法の比較関数でソートの定義をする手法を使ってます
(やはり使いやすいので)。
ちょっと長くなりますが、ご容赦ください。
unit Unit1;
interface
uses
Windows, Controls, StdCtrls, Classes, Forms, SysUtils;
type
TMyRec = Packed Record
A: Array[1..4] of Char;
B: Array[1..6] of Char;
C: Array[1..5] of Char;
D: Array[1..5] of Char;
E: Array[1..5] of Char;
F: Array[1..5] of Char;
CrLf: Array[1..2] of Char;
end;
TMyRecArray = array of TMyRec;
TArraySortCompare = function (Item1, Item2: TMyRec): Integer;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
FRecArray: TMyRecArray;
procedure DataLoadFromFile(const FileName: string);
procedure DataSaveToFile(const FileName: string);
procedure DataSort(Compare: TArraySortCompare);
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.DataLoadFromFile(const FileName: string);
var
FFile:TFileStream;
Len: integer;
begin
FFile := TFileStream.Create(FileName, fmOpenRead or fmShareExclusive);
try
Len := FFile.Size div SizeOf(TMyRec);
SetLength(FRecArray, Len);
FFile.Read(FRecArray[0], SizeOf(TMyRec) * Len);
finally
FFile.Free;
end;
end;
procedure TForm1.DataSaveToFile(const FileName: string);
var
FFile:TFileStream;
Len: integer;
begin
FFile := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
try
Len := SizeOf(TMyRec) * Length(FRecArray);
FFile.Write(FRecArray[0], Len);
finally
FFile.Free;
end;
end;
procedure QuickSort(SorTArray: TMyRecArray; L, R: Integer;
SCompare: TArraySortCompare);
var
I, J: Integer;
P, T: TMyRec;
begin
repeat
I := L;
J := R;
P := SorTArray[(L + R) shr 1];
repeat
while SCompare(SorTArray[I], P) < 0 do Inc(I);
while SCompare(SorTArray[J], P) > 0 do Dec(J);
if I <= J then
begin
T := SorTArray[I];
SorTArray[I] := SorTArray[J];
SorTArray[J] := T;
Inc(I);
Dec(J);
end;
until I > J;
if L < J then QuickSort(SorTArray, L, J, SCompare);
L := I;
until I >= R;
end;
procedure TForm1.DataSort(Compare: TArraySortCompare);
var
Len: Integer;
begin
Len := Length(FRecArray);
if Assigned(Compare) and (FRecArray <> nil) and (Len > 0) then
QuickSort(FRecArray, 0, Len - 1, Compare);
end;
function MyCompare(Item1, Item2: TMyRec): Integer;
begin
Result := CompareStr(Item1.B, Item2.B);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
DataLoadFromFile('FILE1.TXT');
DataSort(MyComPare);
DataSaveToFile('FILE2.TXT');
end;
end.
1行目に
A B C D E F
がある場合は、これを読み飛ばす処理を追加する必要があります。
訂正です。
最後の方の、
procedure TForm1.Button3Click(Sender: TObject);
の部分は、
procedure TForm1.Button1Click(Sender: TObject);
にしてください。
hatenaさん、長いコードまで教授頂き有り難う御座いました。
大変、理解に役立ちました。
m(_ _)m!