Delphi X3 introduces a very cool language extension, which is Record Helpers for simple types. So you can add a set of fields, properties or methods to strings, integers, Double, TDateTime and so on.
In this post I will show you the TStringHelper record helper for the string type defined in the System.SysUtils unit. Take a look to the definition of this record helper.
TStringHelper = record helper for string
private
function GetChars(Index: Integer): Char; inline;
function GetLength: Integer; inline;
class function CharInArray(const C: Char; const InArray: array of Char): Boolean; static;
function IndexOfAny(const Values: array of string; var Index: Integer): Integer; overload;
public
const Empty = '';
// Methods
class function Create(C: Char; Count: Integer): string; overload; inline; static;
class function Create(const Value: array of Char; StartIndex: Integer; Length: Integer): string; overload; static;
class function Create(const Value: array of Char): string; overload; static;
class function Compare(const StrA: string; const StrB: string): Integer; overload; static;
class function Compare(const StrA: string; const StrB: string; IgnoreCase: Boolean): Integer; overload; static;
class function Compare(const StrA: string; IndexA: Integer; const StrB: string; IndexB: Integer; Length: Integer): Integer; overload; static;
class function Compare(const StrA: string; IndexA: Integer; const StrB: string; IndexB: Integer; Length: Integer; IgnoreCase: Boolean): Integer; overload; static;
class function CompareOrdinal(const strA: string; const strB: string): Integer; overload; static;
class function CompareOrdinal(const strA: string; indexA: Integer; const strB: string; indexB: Integer; length: Integer): Integer; overload; static;
function CompareTo(const strB: string): Integer;
function Contains(const Value: string): Boolean;
class function Copy(const Str: string): string; inline; static;
procedure CopyTo(SourceIndex: Integer; var destination: array of Char; DestinationIndex: Integer; Count: Integer);
class function EndsText(const ASubText, AText: string): Boolean; static;
function EndsWith(const Value: string): Boolean; overload;
function EndsWith(const Value: string; IgnoreCase: Boolean): Boolean; overload;
function Equals(const Value: string): Boolean; overload;
class function Equals(const a: string; const b: string): Boolean; overload; static;
class function Format(const Format: string; const args: array of const): string; overload; static;
function GetHashCode: Integer;
function IndexOf(value: Char): Integer; overload; inline;
function IndexOf(const Value: string): Integer; overload; inline;
function IndexOf(Value: Char; StartIndex: Integer): Integer; overload;
function IndexOf(const Value: string; StartIndex: Integer): Integer; overload;
function IndexOf(Value: Char; StartIndex: Integer; Count: Integer): Integer; overload;
function IndexOf(const Value: string; StartIndex: Integer; Count: Integer): Integer; overload;
function IndexOfAny(const AnyOf: array of Char): Integer; overload;
function IndexOfAny(const AnyOf: array of Char; StartIndex: Integer): Integer; overload;
function IndexOfAny(const AnyOf: array of Char; StartIndex: Integer; Count: Integer): Integer; overload;
function Insert(StartIndex: Integer; const Value: string): string;
function IsDelimiter(const Delimiters: string; Index: Integer): Boolean;
function IsEmpty: Boolean;
class function IsNullOrEmpty(const Value: string): Boolean; static;
class function IsNullOrWhiteSpace(const Value: string): Boolean; static;
class function Join(const Separator: string; const values: array of const): string; overload; static;
class function Join(const Separator: string; const Values: array of string): string; overload; static;
class function Join(const Separator: string; const Values: IEnumerable): string; overload; static;
class function Join(const Separator: string; const value: array of string; StartIndex: Integer; Count: Integer): string; overload; static;
function LastDelimiter(const Delims: string): Integer;
function LastIndexOf(Value: Char): Integer; overload;
function LastIndexOf(const Value: string): Integer; overload;
function LastIndexOf(Value: Char; StartIndex: Integer): Integer; overload;
function LastIndexOf(const Value: string; StartIndex: Integer): Integer; overload;
function LastIndexOf(Value: Char; StartIndex: Integer; Count: Integer): Integer; overload;
function LastIndexOf(const Value: string; StartIndex: Integer; Count: Integer): Integer; overload;
function LastIndexOfAny(const AnyOf: array of Char): Integer; overload;
function LastIndexOfAny(const AnyOf: array of Char; StartIndex: Integer): Integer; overload;
function LastIndexOfAny(const AnyOf: array of Char; StartIndex: Integer; Count: Integer): Integer; overload;
function PadLeft(TotalWidth: Integer): string; overload; inline;
function PadLeft(TotalWidth: Integer; PaddingChar: Char): string; overload; inline;
function PadRight(TotalWidth: Integer): string; overload; inline;
function PadRight(TotalWidth: Integer; PaddingChar: Char): string; overload; inline;
function Remove(StartIndex: Integer): string; overload; inline;
function Remove(StartIndex: Integer; Count: Integer): string; overload; inline;
function Replace(OldChar: Char; NewChar: Char): string; overload;
function Replace(OldChar: Char; NewChar: Char; ReplaceFlags: TReplaceFlags): string; overload;
function Replace(const OldValue: string; const NewValue: string): string; overload;
function Replace(const OldValue: string; const NewValue: string; ReplaceFlags: TReplaceFlags): string; overload;
function Split(const Separator: array of Char): TArray; overload;
function Split(const Separator: array of Char; Count: Integer): TArray; overload;
function Split(const Separator: array of Char; Options: TStringSplitOptions): TArray; overload;
function Split(const Separator: array of string; Options: TStringSplitOptions): TArray; overload;
function Split(const Separator: array of Char; Count: Integer; Options: TStringSplitOptions): TArray; overload;
function Split(const Separator: array of string; Count: Integer; Options: TStringSplitOptions): TArray; overload;
function StartsWith(const Value: string): Boolean; overload;
function StartsWith(const Value: string; IgnoreCase: Boolean): Boolean; overload;
function Substring(StartIndex: Integer): string; overload;
function Substring(StartIndex: Integer; Length: Integer): string; overload;
function ToCharArray: TArray; overload;
function ToCharArray(StartIndex: Integer; Length: Integer): TArray; overload;
function ToLower: string;
function ToLowerInvariant: string;
function ToUpper: string;
function ToUpperInvariant: string;
function Trim: string; overload;
function Trim(const TrimChars: array of Char): string; overload;
function TrimEnd(const TrimChars: array of Char): string;
function TrimStart(const TrimChars: array of Char): string;
property Chars[Index: Integer]: Char read GetChars;
property Length: Integer read GetLength;
end;
Note : The same rules for the class and record helpers applies, so you can define multiple helpers with a single type. However, only zero or one helper applies in any specific location in source code and only the record helper defined in the nearest scope will apply. The record helper scope is determined in the normal Delphi fashion (for example, right to left in the unit’s uses clause).
As you can see most of the strings related methods now are part of the string type, so now you can write code like this.
{$APPTYPE CONSOLE}
uses
System.SysUtils;
var
s,s1 :string;
begin
try
// Length property
s:='Hello Delphi XE3';
Writeln(Format('the string Length is %d',[s.Length]));
Writeln('The length of this literal string is '.Length);
//function Contains
if s.Contains('Delphi') then
Writeln(Format('the string "%s" contains the string "%s"',[s,'Delphi']));
//function EndsWith
if s.EndsWith('XE3') then
Writeln(Format('the string "%s" ends with the string "%s"',[s,'XE3']));
//function ToLower
Writeln(Format('using ToLower %s',[s.ToLower]));
//function ToUpper
Writeln(Format('using ToUpper %s',[s.ToUpper]));
//function IndexOf
Writeln(Format('The index of H is %d',[s.IndexOf('H')])); //the value is based in a zero index
//function LastDelimiter
Writeln(Format('The first occurence of any of these chars "abcdef" is %d',[s.IndexOfAny(['a','b','c','d','e','f'])])); //the value is based in a zero index
//function LastDelimiter
Writeln(Format('The last occurence of any of these chars "abcdef" is %d',[s.LastDelimiter('abcdef')])); //the value is based in a zero index
//function Remove
Writeln(Format('The string with only the first 5 chars is %s',[s.Remove(5)])); //the value is based in a zero index
//function Replace
Writeln(Format('Replacing the white spaces for "-", the string becomes %s',[s.Replace(' ','-')])); //the value is based in a zero index
//function split
Writeln;
Writeln('Testing the split function');
for s1 in s.Split([' ']) do
Writeln(s1);
Writeln;
//function Substring
Writeln(Format('The sub string starting in the index 6 is "%s"',[s.Substring(6)])); //the value is based in a zero index
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
Note : All the methods and properties of the System.SysUtils.TStringHelper are zero based index, so be careful when you uses functions like CopyTo, IndexOf, IndexOfAny, Insert, Join, LastDelimiter, LastIndexOf, LastIndexOfAny, Remove, Substring, ToCharArray and the Chars property.
Finally exist a few set of record helpers included in the RTL code which you can use
- System.Classes – TUInt32Helper = record helper for UInt32
- System.SyncObjs – TCriticalSectionHelper = record helper for TRTLCriticalSection
- System.SyncObjs – TConditionVariableHelper = record helper for TRTLConditionVariable
- System.Mac.CFUtils – CFGregorianDateHelper = record helper for CFGregorianDate
- System.SysUtils – TGuidHelper = record helper for TGUID
- System – TSingleHelper = record helper for Single
- System – TDoubleHelper = record helper for Double
- System – TExtendedHelper = record helper for Extended
- Winapi.D2D1 – D2DMatrix3x2FHelper = record helper for TD2DMatrix3X2F
- Vcl.Themes – TElementMarginsHelper = record helper for TElementMargins







