TStringListのName=Value形式を使って一時的に文字列を保持する
|
103 |
StringListNameValue |
動作確認 |
Delphi2007 |
更新日 |
2010/07/04(日) |
TStringListは項目に[Name=Value]の形式、
つまり[タイトル=値]の形式で文字列を格納する
独自の機能を持ちます。
値の取得、値の登録(上書き/追加)
タイトルのIndexを取得、Indexによるタイトルを取得
の機能があり、それぞれ動作確認してみました。
────────────────────
procedure VariantCheck(A, B: Variant);
begin
if not(A = B) then
begin
Assert(False,
'not equal' + #13#10 +
'A=' + String(A) + #13#10 +
'B=' + String(B));
end;
end;
procedure Check(A, B: String); overload;
begin
VariantCheck(A, B);
end;
procedure Check(A, B: Integer); overload;
begin
VariantCheck(A, B);
end;
procedure TForm24.Button3Click(Sender: TObject);
var
StringList1: TStringList;
begin
StringList1 := TStringList.Create; try
StringList1.Clear;
StringList1.Add('タイトル1=値1');
StringList1.Add('タイトル2=値2');
StringList1.Add('タイトル3=値3');
StringList1.Add('タイトル4='); //空文字を登録した特殊項目
StringList1.Add('タイトル5'); //Name=Value形式じゃない項目
//・値を取得する
Check('値1', StringList1.Values['タイトル1']);
Check('値2', StringList1.Values['タイトル2']);
Check('', StringList1.Values['タイトル4']);
Check('', StringList1.Values['タイトル5']);
//※タイトル4はName=空文字形式なので空文字
// タイトル5はName=Value形式ではないので空文字が返ります
//・値を上書き登録する
StringList1.Values['タイトル1'] := '値A';
Check('値A', StringList1.Values['タイトル1']);
Check('タイトル1=値A', StringList1.Strings[0]);
//※該当タイトルの行が更新されます。
//・値を追加登録する
StringList1.Values['タイトル6'] := '値6';
Check('値6', StringList1.Values['タイトル6']);
Check('タイトル6=値6', StringList1.Strings[5]);
//※新しいタイトルの場合は最下行に行が追加されます
//・空文字の値を追加登録してみようとする。
Check(6, StringList1.Count);
StringList1.Values['タイトル7'] := '';
Check('', StringList1.Values['タイトル7']);
Check(6, StringList1.Count);
//※Valueが空文字の場合は追加されません。
//・空文字の値を上書き登録してみようとする。
StringList1.Values['タイトル2'] := '';
Check('', StringList1.Values['タイトル2']);
Check(5, StringList1.Count);
//※空文字を代入するとName=Valueの行全体が削除される
//・タイトルからIndexを求める
Check(0, StringList1.IndexOfName('タイトル1'));
Check(-1, StringList1.IndexOfName('タイトル2'));
Check(1, StringList1.IndexOfName('タイトル3'));
Check(2, StringList1.IndexOfName('タイトル4'));
Check(-1, StringList1.IndexOfName('タイトル5'));
Check(3, StringList1.IndexOf ('タイトル5'));
Check(4, StringList1.IndexOfName('タイトル6'));
//※タイトル4はName=空文字形式だがIndexOfNameは有効
// タイトル5はName=Value形式ではないので無視されます
//・値を追加登録する
StringList1.Values['タイトル5'] := '値5';
Check('値5', StringList1.Values['タイトル5']);
Check('タイトル5', StringList1.Strings[3]);
Check('タイトル5=値5', StringList1.Strings[5]);
//※タイトル5の場合は、Name=Value形式ではないので
// 新しいタイトルとみなされて行が追加されます
//Indexによってタイトルを取得する
Check('タイトル1', StringList1.Names[0]);
Check('タイトル3', StringList1.Names[1]);
Check('タイトル4', StringList1.Names[2]);
Check('', StringList1.Names[3]);
Check('タイトル6', StringList1.Names[4]);
Check('タイトル5', StringList1.Names[5]);
//※タイトル4はName=空文字形式だがNames[]は有効
// タイトル5はName=Value形式ではないので空文字が返ります
Check('タイトル1=値A', StringList1[0]);
Check('タイトル3=値3', StringList1[1]);
Check('タイトル4=', StringList1[2]);
Check('タイトル5', StringList1[3]);
Check('タイトル6=値6', StringList1[4]);
Check('タイトル5=値5', StringList1[5]);
//空文字を取得しようとする
Check(6, StringList1.Count);
Check('', StringList1.Values['']);
Check(-1, StringList1.IndexOfName(''));
//※空文字が取得される
StringList1.Add(''); //空行を追加
StringList1.Add('タイトル7=値7');
Check(8, StringList1.Count);
//空行を検索
Check('', StringList1.Values['']);
Check(-1, StringList1.IndexOfName(''));
Check('', StringList1.Names[6]);
Check('タイトル7', StringList1.Names[7]);
//※空行の検索はできない。
//大小文字が異なる場合の動作
StringList1.Values['titleA'] := 'ValueA';
Check('ValueA', StringList1.Values['TITLea']);
//※タイトルの大小文字が異なっていても値は取得できる
finally StringList1.Free; end;
end;
────────────────────
Namesは読み取り専用プロパティなので、
Namesに代入してタイトルを変更することはできません。
テストコードを各仕様の詳細を知るために利用してください。
Name=Valueではない単なる行の形式や
Name=空文字の形式
Value/IndexOfNameに空文字を代入した場合の動作、
Namesで空行を指定した場合の動作、
タイトルに大文字小文字が異なる値を使った場合の動作など
は動作確認しないとなかなかわかりにくい仕様です。
ともかく、StringListには、このような機能があるので、
名前と値を関連づけて管理することが容易になっています。
これを使って
一時的に文字列と値を保持するリストを作ってみましょう。
次のユニットを使うことで
SetNameValue('タイトル1', '値1');
としておいて値を保持する事ができ、
GetNameValue('タイトル1');
とすることで保持した値を取り出すことができます。
────────────────────
unit NameValue;
interface
uses
Classes;
type TGetNameValueFlag = (gfRemove, gfNoRemove);
procedure SetNameValue(Title, Value: String);
function GetNameValue(Title: String; Flag: TGetNameValueFlag = gfRemove): String;
//テスト用
//function NameValueList: TStringList;
var uNameValueList: TStringList;
implementation
//var uNameValueList: TStringList;
function NameValueList: TStringList;
begin
if not Assigned(uNameValueList) then
uNameValueList := TStringList.Create;
Result := uNameValueList;
end;
procedure SetNameValue(Title, Value: String);
begin
if (Title = '') then
raise Exception.Create('EmptyStr Error: SetNameValue');
NameValueList.Values[Title] := Value;
end;
function GetNameValue(Title: String; Flag: TGetNameValueFlag = gfRemove): String;
var
Index: Integer;
begin
if (Title = '') then
raise Exception.Create('EmptyStr Error: GetNameValue');
Result := NameValueList.Values[Title];
if Flag = gfRemove then
begin
Index := NameValueList.IndexOfName(Title);
if Index <> -1 then
NameValueList.Delete(Index);
end;
end;
initialization
uNameValueList := nil;
finalization
if Assigned(uNameValueList) then
uNameValueList.Free;
end.
{----------------------------------------
//テストコード
procedure testNameValue;
begin
//いきなりGetする
Check('', GetNameValue('test'));
FreeAndNil(uNameValueList);
//いきなりCountを求める
Check(0, NameValueList.Count);
FreeAndNil(uNameValueList);
//値を取得
SetNameValue('test1', 'A');
SetNameValue('test2', 'B');
Check(2, NameValueList.Count);
Check('A', GetNameValue('test1'));
//取得後Countが減っている事を確認
Check(1, NameValueList.Count);
//タイトルに無いものを取得した場合
Check('', GetNameValue('test3'));
Check(1, NameValueList.Count);
//空文字が返り、Countの増減はない
//空文字をValueとして登録する
SetNameValue('test3', '');
Check(1, NameValueList.Count);
//Countは増えない
SetNameValue('test1', 'A');
SetNameValue('test2', 'B');
SetNameValue('test3', 'C');
Check(3, NameValueList.Count);
//値を書き換える
SetNameValue('test2', 'd');
Check(3, NameValueList.Count);
Check('d', GetNameValue('test2'));
Check(2, NameValueList.Count);
//カウントに変化はなく、値は変更されている
//値を削除せずに取得する
Check('A', GetNameValue('test1', gfNoRemove));
Check(2, NameValueList.Count);
//大文字でも取得できる
Check('C', GetNameValue('TEST3', gfNoRemove));
//空文字を代入する
Check(2, NameValueList.Count);
SetNameValue('TEST1', '');
Check(1, NameValueList.Count);
//登録が削除される
end;
//----------------------------------------}
────────────────────
GetNameValueにgfNoRemoveの引数を指定しなければ、
取り出した値はすぐに削除されます。
SetNameValue('タイトル1', '');
このようにすると、値を削除することもできます。
テストコードを参考にしてください。
NameValueListというTStringListのSingletonオブジェクトを
生成して使っていますが、
関数呼び出しする側の利用者にはわからないようになっています。
参考────────────────────
Delphi Tips - TStrings オブジェクトの使用方法
http://support.codegear.com/article/35959/
Strings を使用した関連する値の格納
Singleton オブジェクトの作り方
http://delfusa.main.jp/delfusafloor2/technic/technic/094_Singleton.html
|