Append 系列:萬能型別追加器
TStringBuilder.Append 以多重載支援幾乎所有內建型別直接追加:字串、字元、數值、布林、物件、陣列區段等,內部自動轉換為字串表示,構建高效字串建構管線。
核心 Append 重載分類
| 類別 | 代表重載 | 說明 |
| 字串/字元 | Append(const Value: string), Append(Value: Char), Append(Value: Char; Count: Integer) | 基礎追加、重複字元 |
| 數值型別 | Append(Value: Integer/Int64/UInt64/Single/Double/Extended) | 直接追加數值字串化 |
| 布林值 | Append(Value: Boolean) | 追加 'True'/'False' |
| 物件 | Append(Value: TObject) | 追加 ClassName (或 ToString) |
| 陣列區段 | Append(const Value: array of Char; StartIndex, Count: Integer), Append(const Value: string; StartIndex, Count: Integer) | 部分陣列/字串追加 |
| 換行 | AppendLine, AppendLine(const Value: string) | 追加值 + 平台換行符 |
| 格式化 | AppendFormat(const Format: string; const Args: array of const) | 類 Format 格式化追加 |
完整實作程式碼
procedure TForm1.Button1Click(Sender: TObject); // 基礎型別追加
var sb1, sb2: TStringBuilder; ver: Cardinal;
begin
sb1 := TStringBuilder.Create;
sb2 := TStringBuilder.Create;
try
sb1.Append('Delphi ');
ver := 2009;
sb1.Append(ver); // Cardinal 直接追加
ShowMessage(sb1.ToString); // 'Delphi 2009'
sb2.Append(sb1); // 追加另一 StringBuilder
sb2.AppendLine; // 換行
sb2.Append(Self); // 追加物件 → 'TForm1'
ShowMessage(sb2.ToString); // 'Delphi 2009' + sLineBreak + 'TForm1'
finally
sb1.Free; sb2.Free;
end;
end;
procedure TForm1.Button2Click(Sender: TObject); // 陣列/字串區段追加
const
CharArr: array[0..6] of Char = ('A','B','C','D','E','F','G');
Str = 'ABCDEFG';
var sb: TStringBuilder;
begin
sb := TStringBuilder.Create;
try
sb.Append(CharArr, 2, 3); // 從索引 2 取 3 個 → 'CDE'
ShowMessage(sb.ToString);
sb.Length := 0; // 清空
sb.Append(Str, 2, 3); // 字串區段同樣 → 'CDE'
ShowMessage(sb.ToString);
finally sb.Free; end;
end;
procedure TForm1.Button3Click(Sender: TObject); // 重複字元
var sb: TStringBuilder;
begin
sb := TStringBuilder.Create;
try
sb.Append('A', 10); // 'AAAAAAAAAA'
ShowMessage(sb.ToString);
finally sb.Free; end;
end;
procedure TForm1.Button4Click(Sender: TObject); // 其他型別
var sb: TStringBuilder; b: Boolean; r: Real;
begin
sb := TStringBuilder.Create;
try
b := True; sb.Append(b); sb.AppendLine; // 'True' + 換行
b := False; sb.Append(b); sb.AppendLine; // 'False' + 換行
r := 100/3; sb.Append(r); // '33.3333333333333'
ShowMessage(sb.ToString);
finally sb.Free; end;
end;
procedure TForm1.Button5Click(Sender: TObject); // AppendFormat
var sb: TStringBuilder;
begin
sb := TStringBuilder.Create;
try
sb.AppendFormat('%s %d', ['Delphi', 2009]); // 同 Format 函數
ShowMessage(sb.ToString); // 'Delphi 2009'
finally sb.Free; end;
end;
AppendFormat 格式化字串詳解
AppendFormat(const Format: string; const Args: array of const) 語法與 SysUtils.Format 完全相容:
| 格式項 | 說明 | 範例 |
%s | 字串 | AppendFormat('Hi %s', ['Tom']) |
%d | 整數 | AppendFormat('Age %d', [25]) |
%f | 浮點數 | AppendFormat('Pi %.2f', [3.14159]) |
%x/%X | 十六進位 | AppendFormat('0x%X', [255]) |
%p | 指標地址 | AppendFormat('Ptr %p', [Pointer(obj)]) |
%% | 字面 % | AppendFormat('100%%') |
進階應用場景
1. 高效日誌建構器
type
TLogBuilder = class
private FSB: TStringBuilder;
public
constructor Create; begin FSB := TStringBuilder.Create(1024); end;
destructor Destroy; begin FSB.Free; end;
procedure Log(const Msg: string); begin FSB.AppendLine('['+FormatDateTime('hh:nn:ss.zzz', Now)+'] '+Msg); end;
procedure LogFmt(const Fmt: string; const Args: array of const); begin FSB.AppendFormat('['+FormatDateTime('hh:nn:ss.zzz', Now)+'] '+Fmt, Args); FSB.AppendLine; end;
function GetText: string; begin Result := FSB.ToString; end;
procedure Clear; begin FSB.Length := 0; end;
end;
2. SQL 參數化建構 (防注入輔助)
function BuildWhereClause(const Conditions: TDictionary): string;
var
sb: TStringBuilder;
pair: TPair;
first: Boolean;
begin
sb := TStringBuilder.Create(256);
try
first := True;
for pair in Conditions do
begin
if not first then sb.Append(' AND ');
sb.Append(pair.Key).Append(' = ');
case VarType(pair.Value) of
varString, varUString: sb.Append(''').Append(pair.Value).Append('''');
varInteger, varInt64: sb.Append(pair.Value);
varDate: sb.Append('#').Append(FormatDateTime('yyyy-mm-dd', pair.Value)).Append('#');
else sb.Append(pair.Value);
end;
first := False;
end;
Result := sb.ToString;
finally sb.Free; end;
end;
3. 程式碼產生器:縮排管理
type
TCodeBuilder = class
private
FSB: TStringBuilder;
FIndent: Integer;
FIndentStr: string;
public
constructor Create; begin FSB := TStringBuilder.Create; FIndentStr := ' '; end;
destructor Destroy; begin FSB.Free; end;
procedure Indent; begin Inc(FIndent); end;
procedure Unindent; begin Dec(FIndent); end;
procedure WriteLine(const Line: string);
begin
FSB.Append(FIndentStr, FIndent); // 重複縮排字串
FSB.AppendLine(Line);
end;
function GetCode: string; begin Result := FSB.ToString; end;
end;
4. 物件序列化輔助
procedure DumpObject(sb: TStringBuilder; Obj: TObject; Indent: Integer = 0);
var
ctx: TRttiContext;
typ: TRttiType;
prop: TRttiProperty;
pad: string;
begin
pad := StringOfChar(' ', Indent * 2);
sb.AppendLine(pad + Obj.ClassName);
ctx := TRttiContext.Create;
try
typ := ctx.GetType(Obj.ClassInfo);
for prop in typ.GetProperties do
if prop.IsReadable then
sb.AppendFormat('%s%s = %s', [pad + ' ', prop.Name, prop.GetValue(Obj).ToString]);
finally ctx.Free; end;
end;
效能優化關鍵技巧
| 技巧 | 程式碼 | 效果 |
| 預分配容量 | TStringBuilder.Create(預估字元數) | 避免多次擴容複製 |
| 批次追加用 AppendFormat | sb.AppendFormat('%s=%d;%s=%d', [k1,v1,k2,v2]) | 單次格式化 vs 多次 Append |
| 重複字元用 Append(c, n) | sb.Append(' ', Indent*2) | 避免迴圈 Append |
| 清空重用用 Length := 0 | sb.Length := 0 | 保留容量,避免 Free/Create |
| EnsureCapacity 擴容提示 | sb.EnsureCapacity(sb.Length + 1000) | 大量追加前預留 |
常見陷阱與避坑
| 陷阱 | 後果 | 正確做法 |
| Append(Object) 非預期輸出 | 輸出 ClassName 而非業務內容 | 覆寫 ToString 或手動 Append 屬性 |
| AppendFormat 參數個數不符 | EFormatError | 嚴格對應 % 佔位符與 Args 元素 |
| Real/Extended 精度截斷 | 科學計數法或截斷 | 用 FormatSettings 或 %.nf 指定精度 |
| Char 陣列區段索引越界 | AV/例外 | 檢查 StartIndex+Count <= Length(Arr) |
總結
TStringBuilder.Append 以龐大重載家族實現「萬能追加」,AppendFormat 提供格式化追加。掌握型別直追加、陣列區段、重複字元、物件追加行為、格式化語法五大核心模式,配合預分配容量、Length:=0 重用、AppendFormat 批次三大效能技巧,即能構建高效、可維護的字串建構管線:日誌、SQL、程式碼產生、序列化、報表生成等場景皆受益。