Strings & String Routines
Long strings are reference-counted with copy-on-write: assigning is cheap, and the data is copied only when one of the variables is modified.
17.1 Basics
Long strings are reference-counted with copy-on-write: assigning is cheap, and the data is copied only when one of the variables is modified.
var
S, T: string;
begin
S := 'Hello';
T := S + ', World'; // concatenation
Writeln(Length(T)); // 12
Writeln(T[1]); // H (1-based)
T[1] := 'J'; // copy-on-write: S is unaffected
Writeln(S, ' / ', T); // Hello / Jello, World
if S = 'Hello' then Writeln('equal'); // case-sensitive comparison
end.17.2 Classic string routines
number of chars (code units) Length('abc') = 3 Copy(S, Index, Count) Copy('Pascal', 2, 3) = 'asc' first position, 0 if absent Pos('c', 'Pascal') = 4 Pos(Sub, S, Offset) / PosEx System / StrUtils search from an offset Delete(S, Index, Count) remove chars in place Insert(Sub, S, Index) insert in place SetLength(S, N) StringOfChar(C, N) StringOfChar('-', 5) UpperCase, LowerCase ASCII case conversion AnsiUpperCase, AnsiLowerCase locale-aware case conversion Trim, TrimLeft, TrimRight remove whitespace/control chars StringReplace(S, Old, New, Flags) replace ([rfReplaceAll, rfIgnoreCase]) CompareStr, CompareText, SameText case-sensitive / insensitive compare IntToStr, StrToInt, Format wrap in quotes, doubling inner quotes LeftStr, RightStr, MidStr ReverseString, DupeString reverse, repeat
StartsText, EndsText, ContainsText split into an array (Delphi; in FPC use S.Split)
program StringOps;
{$mode objfpc}{$H+}
uses SysUtils, StrUtils;
var
S: string;
begin
S := ' Free Pascal is fun ';
S := Trim(S);
Writeln('[', S, ']'); // [Free Pascal is fun]
Writeln(UpperCase(S)); // FREE PASCAL IS FUN
Writeln(Pos('Pascal', S)); // 6
Writeln(Copy(S, 6, 6)); // Pascal
Writeln(StringReplace(S, 'fun', 'fast', [rfReplaceAll]));
Writeln(ReverseString('stressed')); // desserts
Writeln(DupeString('ab', 3)); // ababab
Delete(S, 1, 5);
Writeln(S); // Pascal is fun
Insert('Object ', S, 1);
Writeln(S); // Object Pascal is fun
end.17.3 String helper methods
Delphi XE3+ and FPC 3.0+ (SysUtils) provide a record helper for string with method syntax and 0-based indexes:
Mixing 1-based Copy/Pos and 0-based helper methods is a common source of off-by-one bugs — pick one style per code base.
var
S: string;
Parts: TStringArray; // FPC; Delphi: TArray<string>
P: string;
begin
S := 'red,green,blue';
Writeln(S.ToUpper); // RED,GREEN,BLUE
Writeln(S.Contains('green')); // TRUE
Writeln(S.IndexOf('green')); // 4 (0-based!)
Writeln(S.Replace(',', ';'));
Parts := S.Split([',']);
for P in Parts do Writeln(P.Trim);
Writeln(S.StartsWith('red'), ' ', S.Length);
end.17.4 Splitting with TStringList
uses Classes;
var
SL: TStringList;
I: Integer;
begin
SL := TStringList.Create;
try
SL.Delimiter := ';';
SL.StrictDelimiter := True; // do not also split on spaces
SL.DelimitedText := 'alpha;beta gamma;delta';
for I := 0 to SL.Count - 1 do
Writeln(I, ': ', SL[I]);
SL.CommaText := 'x=1,y=2';
Writeln(SL.Values['y']); // 2
finally
SL.Free;
end;
end.17.5 Building strings efficiently
Repeated S := S + X in a long loop reallocates memory; it is acceptable for small loops (the memory manager is good at it) but for large outputs use TStringBuilder (Delphi System.SysUtils; FPC 3.2 SysUtils) or a TStringList:
var
SB: TStringBuilder;
I: Integer;
begin
SB := TStringBuilder.Create;
try
for I := 1 to 1000 do
SB.Append(I).Append(',');
Writeln(Length(SB.ToString));
finally
SB.Free;
end;
end.17.6 Unicode and encodings
Delphi string is UTF-16: Length counts UTF-16 code units; characters outside the BMP (emoji) take two (a surrogate pair).
Lazarus/FPC objfpc programs use UTF-8 in AnsiString: Length counts bytes. Use UTF8Length, UTF8Copy, UTF8UpperCase from the LazUTF8 unit for character-based operations.
Convert explicitly: UTF8Encode/UTF8Decode, TEncoding.UTF8.GetBytes, UTF8ToString (Delphi), or assignment between UnicodeString and UTF8String (the compiler converts).
Files: TStringList.SaveToFile(Name, TEncoding.UTF8); Delphi's TFile.ReadAllText(Name, TEncoding.UTF8).
17.7 ShortString and PChar
PChar(S) of an empty string returns a pointer to a #0 character, never nil, so it is always safe to pass to C APIs.
var
SS: string[20]; // ShortString with max length 20
P: PChar;
Buf: array[0..63] of Char;
S: string;
begin
SS := 'Turbo Pascal';
Writeln(Ord(SS[0])); // 12 — the length byte
S := 'null-terminated';
P := PChar(S); // pointer to the string's characters (valid while S lives)
StrPCopy(Buf, 'copied'); // SysUtils: copy into a char array
Writeln(StrLen(P)); // 15
end.