DelphiDabbler Code Snippets Database

"String Management" Category Contents

The following snippets belong to the String Management category.

AddDefThousandSeparator

Adds the thousands separator for the current locale at the correct location(s) in string S and returns the result. S is assumed to be the string representation of a positive whole number.

function AddDefThousandSeparator(const S: string): string;
begin
  Result := AddThousandSeparator(S, SysUtils.ThousandSeparator);
end;

AddDefThousandSeparatorXE

Adds the thousands separator for the current locale at the correct location(s) in string S and returns the result. S is assumed to be the string representation of a positive whole number.

function AddDefThousandSeparatorXE(const S: string): string;
begin
  Result := AddThousandSeparator(S, SysUtils.FormatSettings.ThousandSeparator);
end;

AddThousandSeparator

Adds the 'thousands separator' specified by C at the correct location(s) in string S and returns the result. S is assumed to be the string representation of a positive whole number.

function AddThousandSeparator(const S: string; const C: Char): string;
var
  I: Integer; // loops through separator position
begin
  Result := S;
  I := Length(S) - 2;
  while I > 1 do
  begin
    Insert(C, Result, I);
    I := I - 3;
  end;
end;

AnsiStringToCharSet

Creates and returns a set of all the unique characters from the given ANSI string.

function AnsiStringToCharSet(const S: RawByteString): TCharSet;
var
  Idx: Integer;  // indexes characters of S
begin
  Result := [];
  for Idx := 1 to Length(S) do
    Include(Result, S[Idx]);
end;

CEscapeStr

Returns a copy of string S which has each character appearing in EscapableChars replaced by an escape sequence comprising the character '\' followed by the corresponding character from EscapeChars.

function CEscapeStr(const S, EscapeChars, EscapableChars: string): string;
const
  cEscChar = '\';       // the C escape character
var
  EscCount: Integer;    // count of escaped characters in string
  Idx: Integer;         // loops thru string
  PRes: PChar;          // points to chars in result string
  EscCharPos: Integer;  // position of esc chars in EscapeChars & EscapableChars
begin
  // Check for empty string and treat specially
  // (empty string crashes main code)
  if S = '' then
  begin
    Result := '';
    Exit;
  end;
  // Count escapable characters in string
  EscCount := 0;
  for Idx := 1 to Length(S) do
  begin
    if SysUtils.AnsiPos(S[Idx], EscapableChars) > 0 then
      Inc(EscCount);
  end;
  // Set size of result string and get pointer to it
  SetLength(Result, Length(S) + EscCount);
  PRes := PChar(Result);
  // Replace escapable chars with the escaped version
  for Idx := 1 to Length(S) do
  begin
    EscCharPos := SysUtils.AnsiPos(S[Idx], EscapableChars);
    if EscCharPos > 0 then
    begin
      PRes^ := cEscChar;
      Inc(PRes);
      PRes^ := EscapeChars[EscCharPos];
    end
    else
      PRes^ := S[Idx];
    Inc(PRes);
  end;
end;

ChangeChar

Replaces all occurrences the character ASearch in AString with the AReplace character, and returns the resulting string.

function ChangeChar(const AString: string; ASearch, AReplace: Char): string;
var
  I: integer; // loops thru all chars of string
begin
  Result := AString;
  if Result = '' then
    Exit;
  for I := 1 to Length(Result) do
    if Result[I] = ASearch then
      Result[I] := AReplace;
end;

CompareNumberStr

Compares two strings, S1 and S2, treating any whole, non-negative, numbers embedded in the strings as numbers rather than text. Text comparisons are case sensitive. Returns a negative value if S1 < S2, a positve value if S1 > S2 or 0 if S1 and S2 are equal.

function CompareNumberStr(const S1, S2: string): Integer;

  // Gets a chunk of all numeric or all non-numeric text from Source starting at
  // Pos and stores in Dest. Pos is moved past the end of the chunk.
  procedure GetChunk(Source: string; var Pos: Integer; out Dest: string);
  var
    IsNum: Boolean; // flags if string chunk is numeric
    DP: Integer;    // cursor into Source string
  begin
    if Pos > Length(Source) then
      Dest := ''
    else
    begin
      IsNum := IsASCIIDigit(Source[Pos]);
      DP := 0;
      while (Pos + DP <= Length(Source))
        and (IsASCIIDigit(Source[Pos + DP]) = IsNum) do
        Inc(DP);
      Dest := Copy(Source, Pos, DP);
      Pos := Pos + DP;
    end;
  end;

var
  Chunk1, Chunk2: string; // chunks of text from S1 and S2 respectively
  Pos1, Pos2: Integer;    // current position in S1 and S2 respectively
begin
  if (S1 = '') or (S2 = '')
    or (IsASCIIDigit(S1[1]) xor IsASCIIDigit(S2[1])) then
    // Either S1 or S2 is empty OR one starts with a digit and the other starts
    // with a non-digit. In either case we just need a normal string compare.
    Result := SysUtils.CompareStr(S1, S2)
  else
  begin
    // Either both S1 and S2 start with digits OR both start with non-digits.
    // Therefore the strings may (or do) contain numbers, so we need special
    // processing.
    Pos1 := 1;
    Pos2 := 1;
    Result := 0;
    repeat
      // Get the first digit only or non-digit only chunks of the strings. If
      // both strings are non empty they will either both be digit strings or
      // both be non-digit strings
      GetChunk(S1, Pos1, Chunk1);
      GetChunk(S2, Pos2, Chunk2);
      if Chunk1 = '' then
      begin
        if Chunk2 <> '' then
          Result := -1;
      end
      else if Chunk2 = '' then
        Result := 1
      else if IsASCIIDigit(Chunk1[1]) then
        // These chunks are both numeric: compare numbers.
        Result := SysUtils.StrToInt(Chunk1) - SysUtils.StrToInt(Chunk2)
      else
        // These chunks are both non-numeric: compare text
        Result := SysUtils.CompareStr(Chunk1, Chunk2);
      // If existing chunks compare same, we move on to compare next chunks,
      // providing we have not run out of text.
    until (Result <> 0) or ((Chunk1 = '') and (Chunk2 = ''));
  end;
end;

CompressWhiteSpace

Returns a copy of the given string where each sequence of one or more white space characters is replaced by a single space character.

function CompressWhiteSpace(const S: string): string;
var
  Idx: Integer;      // loops thru all characters in string
  ResCount: Integer; // counts number of characters in result string
  PRes: PChar;       // pointer to characters in result string
begin
  // Set length of result to length of source string and set pointer to it
  SetLength(Result, Length(S));
  PRes := PChar(Result);
  // Reset count of characters in result string
  ResCount := 0;
  // Loop thru characters of source string
  Idx := 1;
  while Idx <= Length(S) do
  begin
    if IsWhiteSpace(S[Idx]) then
    begin
      // Current char is white space: replace by space char and count it
      PRes^ := ' ';
      Inc(PRes);
      Inc(ResCount);
      // Skip past any following white space
      Inc(Idx);
      while IsWhiteSpace(S[Idx]) do
        Inc(Idx);
    end
    else
    begin
      // Current char is not white space: copy it literally and count it
      PRes^ := S[Idx];
      Inc(PRes);
      Inc(ResCount);
      Inc(Idx);
    end;
  end;
  // Reduce length of result string if it is shorter than source string
  if ResCount < Length(S) then
    SetLength(Result, ResCount);
end;

ContainsDelims

Checks if string S contains any of the characters from the Delimiters string. Returns True if any delimiter character is found or False if not.

function ContainsDelims(const S, Delimiters: string): Boolean;
var
  DelimIdx: Integer;  // loops thru delimiters
begin
  Result := False;
  for DelimIdx := 1 to Length(Delimiters) do
    if SysUtils.AnsiPos(Delimiters[DelimIdx], S) > 0 then
    begin
      Result := True;
      Break;
    end;
end;

ContainsWhiteSpace

Checks if the given string contains any white space.

function ContainsWhiteSpace(const S: string): Boolean;
const
  cWhiteSpace = ' '#9#10#11#12#13;  // white space characters
begin
  Result := ContainsDelims(S, cWhiteSpace);
end;

CountDelims

Returns the number of occurences of any character from Delims in the given string S.

function CountDelims(const S, Delims: string): Integer;
var
  Idx: Integer; //loops thru all characters in string
begin
  Result := 0;
  for Idx := 1 to Length(S) do
    if SysUtils.IsDelimiter(Delims, S, Idx) then
      Inc(Result);
end;

CountUnquotedWords

Returns the number of space delimited words in string S. Any words enclosed by the quote character AQuote are counted as one word.

function CountUnquotedWords(const S: string; const AQuote: Char = '"'): Integer;
begin
  with Classes.TStringList.Create do
  try
    QuoteChar := AQuote;
    Delimiter := ' ';
    DelimitedText := S;
    Result := Count;
  finally
    Free;
  end;
end;

CountWords

Returns the number of white space delimited words in the given string.

function CountWords(const Str: string): Integer;
var
  Words: Classes.TStringList; // list of words in string
begin
  Words := Classes.TStringList.Create;
  try
    ExplodeWords(Str, Words);
    Result := Words.Count;
  finally
    Words.Free;
  end;
end;

CUnEscapeStr

Returns a copy of string S where each C-style escape sequence, introduced by '\' and followed by a character from EscapeChars, is replaced by the corresponding character from EscapableChars. If an unrecognised escape character is found it is copied literally, stripped of its preceeding '\'.

function CUnEscapeStr(const S, EscapeChars, EscapableChars: string): string;
const
  cEscChar = '\';       // the C escape character
var
  EscCount: Integer;    // counts escaped characters in string
  Idx: Integer;         // loops thru source string
  PRes: PChar;          // points to chars in result string
  EscCharPos: Integer;  // position of esc chars in EscapeChars & EscapableChars
begin
  // Count escape sequences
  EscCount := 0;
  Idx := 1;
  while Idx < Length(S) do  // don't count '\' if last character
  begin
    if S[Idx] = cEscChar then
    begin
      Inc(EscCount);
      Inc(Idx);
    end;
    Inc(Idx);
  end;
  // Set length of result string and get pointer to it
  SetLength(Result, Length(S) - EscCount);
  PRes := PChar(Result);
  // Replace escaped chars with literal ones
  Idx := 1;
  while Idx <= Length(S) do
  begin
    // check for escape char (unless last char when treat literally)
    if (S[Idx] = cEscChar) and (Idx <> Length(S)) then
    begin
      // we have an escape char
      Inc(Idx); // skip over '\'
      // get index of escaped char (0 if not valid)
      EscCharPos := SysUtils.AnsiPos(S[Idx], EscapeChars);
      if EscCharPos > 0 then
        PRes^ := EscapableChars[EscCharPos]
      else
        PRes^ := S[Idx];  // invalid escape char: copy literally
    end
    else
      PRes^ := S[Idx];
    Inc(Idx);
    Inc(PRes);
  end;
end;

CutWordByIndex

Deletes the Nth word from string Str and returns the deleted word. Words are delimited by any of the characters in Delims. If there is no Nth word then the empty string is returned and Str is not modified.

function CutWordByIndex(const N: Integer; var Str: string;
  const Delims: TCharSet): string;
var
  St, En: Integer;  // start and end of string to cut
begin
  if GetStartAndEndWord(N, Str, Delims, St, En) then
  begin
    Result := Copy(Str, St, En - St + 1);
    Delete(Str, St, En - St + 1);
  end;
end;

DelAllStr

Deletes all occurrences of sub-string Needle from string HayStack and returns the resulting string. HayStack is returned unchanged if it does not contain Needle. The search is case sensitive.

function DelAllStr(const Needle, Haystack: string): string;
var
  StartIdx: Integer;
begin
  Result := Haystack;
  StartIdx := SysUtils.AnsiPos(Needle, Result);
  while StartIdx > 0 do
  begin
    Delete(Result, StartIdx, Length(Needle));
    StartIdx := SysUtils.AnsiPos(Needle, Result);
  end;
end;

DelAllText

Deletes all occurrences of text Needle from text HayStack and returns the resulting string. HayStack is returned unchanged if it does not contain Needle. The search is case insensitive.

function DelAllText(const Needle, Haystack: string): string;
var
  StartIdx: Integer;
  LowerNeedle: string;
begin
  Result := Haystack;
  LowerNeedle := SysUtils.AnsiLowerCase(Needle);
  StartIdx := SysUtils.AnsiPos(LowerNeedle, SysUtils.AnsiLowerCase(Result));
  while StartIdx > 0 do
  begin
    Delete(Result, StartIdx, Length(Needle));
    StartIdx := SysUtils.AnsiPos(LowerNeedle, SysUtils.AnsiLowerCase(Result));
  end;
end;

DeleteWordByIndex

Deletes and discards the Nth word from string Str. Words are delimited by any of the characters in Delims. Returns True if the Nth word was found and deleted from Str or False if there is no Nth word and Str is unchanged.

function DeleteWordByIndex(const N: Integer; var Str: string;
  const Delims: TCharSet): Boolean;
var
  St, En: Integer; // start and end of string to delete
begin
  Result := GetStartAndEndWord(N, Str, Delims, St, En);
  if Result then
    Delete(Str, St, En - St + 1);
end;

DelStr

Deletes the first occurrence of sub-string Needle from string HayStack and returns the resulting string. HayStack is returned unchanged if it does not contain Needle. The search is case sensitive.

function DelStr(const Needle, Haystack: string): string;
var
  StartIdx: Integer;
begin
  Result := Haystack;
  StartIdx := SysUtils.AnsiPos(Needle, Result);
  if StartIdx > 0 then
    Delete(Result, StartIdx, Length(Needle));
end;

DelText

Deletes the first occurrence of text Needle from text HayStack and returns the resulting string. HayStack is returned unchanged if it does not contain Needle. The search is case insensitive.

function DelText(const Needle, Haystack: string): string;
var
  StartIdx: Integer;
begin
  Result := Haystack;
  StartIdx := SysUtils.AnsiPos(
    SysUtils.AnsiLowerCase(Needle), SysUtils.AnsiLowerCase(Haystack)
  );
  if StartIdx > 0 then
    Delete(Result, StartIdx, Length(Needle));
end;

DOSLineBreaks

Converts all Unix and Mac line endings in the given string to DOS line endings and returns the result.

function DOSLineBreaks(const S: string): string;
begin
  // Replace any existing CRLF (DOS) lines ends with LF
  Result := SysUtils.StringReplace(
    S, #13#10, #10, [SysUtils.rfReplaceAll]
  );
  // Replace any remaining CR (Mac) line ends with LF
  Result := SysUtils.StringReplace(
    Result, #13, #10, [SysUtils.rfReplaceAll]
  );
  // Replace all LF (Unix) lines ends with CRLF
  Result := SysUtils.StringReplace(
    Result, #10, #13#10, [SysUtils.rfReplaceAll]
  );
end;

ExplodeStr

Splits the string S into segments separated by delimiter Delim and stores each segment in turn in string-list List, replacing any existing content. If Trim is True segments are trimmed of leading and trailing spaces. Empty segments (after any trimming) are discarded if AllowEmpty is False. The number of segments added to List is returned.

function ExplodeStr(S, Delim: string; const List: Classes.TStrings;
  const AllowEmpty: Boolean = True; const Trim: Boolean = False): Integer;
var
  Item: string;       // current delimited text
  Remainder: string;  // remaining un-consumed part of string

  // ---------------------------------------------------------------------------
  procedure AddItem;
  begin
    // Adds optionally trimmed item to list if required
    if (Trim) then
      Item := SysUtils.Trim(Item);
    if (Item <> '') or AllowEmpty then
      List.Add(Item);
  end;
  // ---------------------------------------------------------------------------

begin
  // Clear the list
  List.Clear;
  // Check we have some entries in the string
  if S <> '' then
  begin
    // Repeatedly split string until we have no more entries
    while SplitStr(S, Delim, Item, Remainder) do
    begin
      AddItem;
      S := Remainder;
    end;
    // Add any remaining item
    AddItem;
  end;
  Result := List.Count;
end;

ExplodeStrArray

Splits the string S into segments separated by delimiter Delim and returns a string array containing the segments. If Trim is True segments are trimmed of leading and trailing spaces. Empty segments (after any trimming) are discarded if AllowEmpty is False.

function ExplodeStrArray(const S, Delim: string;
  const AllowEmpty: Boolean = True;
  const Trim: Boolean = False): Types.TStringDynArray;
var
  Strings: Classes.TStringList; // intermediate string list for ExplodeStr
begin
  Strings := Classes.TStringList.Create;
  try
    ExplodeStr(S, Delim, Strings, AllowEmpty, Trim);
    Result := StringListToArray(Strings);
  finally
    Strings.Free;
  end;
end;

ExplodeUnquotedWords

Extracts a list of space delimited words from string S and returns the number of words found. The extracted words are stored in stringlist List, overwriting any existing contents. Any words enclosed by the quote character AQuote are kept together as one word.

function ExplodeUnquotedWords(const S: string; const List: Classes.TStrings;
  const AQuote: Char = '"'): Integer;
begin
  List.Clear;
  List.QuoteChar := AQuote;
  List.Delimiter := ' ';
  List.DelimitedText := S;
  Result := List.Count;
end;

ExplodeWords

Extracts a list of white space delimited words from string S and returns the number of words found. The extracted words are stored in stringlist Words, overwriting any existing content.

function ExplodeWords(const S: string; const Words: Classes.TStrings): Integer;
begin
  Result := ExplodeStr(CompressWhiteSpace(S), ' ', Words, False, True);
end;

GetFirstWord

Returns the first word of string S where words are delimited by the character supplied in Delim. If Delim is the space character (the default) then any sequence of white space will act as the word delimiter.

function GetFirstWord(var S: string; const Delim: Char = ' '): string;
var
  AWordCount: Integer;      // number of words in string
  Words: Classes.TStrings;  // list of words in string
begin
  Words := Classes.TStringList.Create;
  try
    AWordCount := ExplodeStr(CompressWhiteSpace(S), Delim, Words, False, True);
    if AWordCount > 0 then
      Result := Words[0]
    else
      Result := '';
  finally
    Words.Free;
  end;
end;

GetLastWord

Returns the last word of string S where words are delimited by the character supplied in Delim. If Delim is the space character (the default) then any sequence of white space will act as the word delimiter.

function GetLastWord(var S: string; const Delim: Char = ' '): string;
var
  AWordCount: Integer;      // number of words in string
  Words: Classes.TStrings;  // list of words in string
begin
  Words := Classes.TStringList.Create;
  try
    AWordCount := ExplodeStr(CompressWhiteSpace(S), Delim, Words, False, True);
    if AWordCount > 0 then
      Result := Words[AWordCount - 1]
    else
      Result := '';
  finally
    Words.Free;
  end;
end;

GetStartAndEndWord

Finds the location of the Nth word in string Str and passes the start and end of the location out in StartIdx and EndIdx. Words are delimited by the any of the characters in Delim. Returns True if the Nth word was found or False, with StartIdx set to 0, if not.

function GetStartAndEndWord(const N: Integer; const Str: string;
  const Delims: TCharSet; out StartIdx, EndIdx: Integer): Boolean;
var
  I, J: Integer;  // loops thru string finding start and end of word
  Count: Integer; // index of found word in string
  SLen: Integer;  // length of string
begin
  Result := False;
  Count := 0;
  I := 1;
  StartIdx := 0;
  EndIdx := 0;
  SLen := Length(Str);
  while I <= SLen do
  begin
    while (I <= SLen) and (IsCharInSet(Str[I], Delims)) do
      Inc(I);
    if I <= SLen then
      Inc(Count);
    J := I;
    while (J <= SLen) and not (IsCharInSet(Str[J], Delims)) do
      Inc( J );
    if Count = N then
    begin
      StartIdx := I;
      EndIdx := J - 1;
      Result := StartIdx > 0;
      Exit;
    end;
    I := J;
  end;
end;

GetWordByIndex

Locates and returns the Nth word from string Str. Words are delimited by the any of the characters in Delim. If there is no Nth word then the empty string is returned.

function GetWordByIndex(const N: Integer; const Str: string;
  const Delims: TCharSet): string;
var
  St, En: Integer;  // start and end of string to find
begin
  if GetStartAndEndWord(N, Str, Delims, St, En) then
    Result := Copy(Str, St, En - St + 1)
  else
    Result := '';
end;

InString

Checks if string Needle is contained in Haystack and returns True if so or False if not. Checking is case insensitive if IgnoreCase is True.

function InString(Haystack, Needle: string; IgnoreCase: Boolean): Boolean;
begin
  if IgnoreCase then
  begin
    Needle := SysUtils.AnsiLowerCase(Needle);
    Haystack := SysUtils.AnsiLowerCase(Haystack);
  end;
  Result := SysUtils.AnsiPos(Needle, Haystack) > 0;
end;

IsHexStr

Checks if the given string contains only valid hex digits. Returns True if so or False otherwise.

function IsHexStr(const S: string): Boolean;
  {Returns true if string S contains only valid hex digits, false otherwise}
const
  cHexChars = ['0'..'9', 'A'..'F', 'a'..'f']; // set of valid hex digits
var
  Idx: Integer; // loops thru all characters in string
begin
  Result := True;
  for Idx := 1 to Length(S) do
    if not IsCharInSet(S[Idx], cHexChars) then
    begin
      Result := False;
      Break;
    end;
end;

IsNumeric

Checks if the string Value contains a valid numeric value and returns True if so or False if not. If AllowFloat is true then Value may contain a floating point number, otherwise it must be an integer. If TrimWhiteSpace is True any white space surrounding Value is trimmed before testing.

function IsNumeric(Value: string; const AllowFloat: Boolean;
  const TrimWhiteSpace: Boolean = True): Boolean;
var
  ValueInt: Int64;      // dummy integer value
  ValueFloat: Extended; // dummy float value
begin
  if TrimWhiteSpace then
    Value := SysUtils.Trim(Value);
  // Check for valid integer
  Result := SysUtils.TryStrToInt64(Value, ValueInt);
  if not Result and AllowFloat then
    // Wasn't valid as integer, try float
    Result := SysUtils.TryStrToFloat(Value, ValueFloat);
end;

IsValidCEscapedStr

Checks if any C-style escape characters in string S match those given by ValidEscChars. Returns True if so and False if not.

function IsValidCEscapedStr(const S, ValidEscChars: string): Boolean;
const
  cEscChar = '\';       // the C escape character
var
  Idx: Integer;         // loops thru chars in string
  EscCharPos: Integer;  // position of esc char in ValidEscChars
begin
  // Assume we fail
  Result := False;
  // Scan through all string
  Idx := 1;
  while Idx <= Length(S) do
  begin
    if (S[Idx] = cEscChar) then
    begin
      // We have an escape char
      if Idx = Length(S) then
        Exit; // error: esc symbol is at end of string
      // skip over escape symbol and test escape char
      Inc(Idx);
      EscCharPos := SysUtils.AnsiPos(S[Idx], ValidEscChars);
      if EscCharPos = 0 then
        Exit; // error: esc char is not recognised
    end;
    Inc(Idx);
  end;
  // Everything is OK
  Result := True;
end;

IsValidDouble

Checks if the given string represents a valid double precision floating point number.

function IsValidDouble(const S: string): Boolean;
var
  Dummy: Double;
begin
  Result := SysUtils.TryStrToFloat(S, Dummy);
end;

IsValidExtended

Checks if the given string represents a valid extended precision floating point number.

function IsValidExtended(const S: string): Boolean;
var
  Dummy: Extended;
begin
  Result := SysUtils.TryStrToFloat(S, Dummy);
end;

IsValidSingle

Checks if the given string represents a valid single precision floating point number.

function IsValidSingle(const S: string): Boolean;
var
  Dummy: Single;
begin
  Result := SysUtils.TryStrToFloat(S, Dummy);
end;

IsWhiteSpace

Checks if the given character is white space.

function IsWhiteSpace(const Ch: Char): Boolean;
begin
  Result := IsCharInSet(Ch, [' ', #9, #10, #11, #12, #13]);
end;

JoinStr

Joins all strings in string list SL together into a single string, which is returned. Strings are separated by delimiter text Delim. Empty strings are ignored unless AllowEmpty is True, when they cause a delimiter to be appended to the result string.

function JoinStr(const SL: Classes.TStrings; const Delim: string;
  const AllowEmpty: Boolean = True): string;
var
  Idx: Integer; // loops thru all items in string list
begin
  Result := '';
  for Idx := 0 to Pred(SL.Count) do
  begin
    if (SL[Idx] <> '') or AllowEmpty then
      if Result = '' then
        Result := SL[Idx]
      else
        Result := Result + Delim + SL[Idx];
  end;
end;

JoinStrArray

Joins all strings in string array Strings together into a single string, which is returned. Strings are separated by delimiter text Delim. Empty strings are ignored unless AllowEmpty is True, when they cause a delimiter to be appended to the result string.

function JoinStrArray(const Strings: array of string; const Delim: string;
  const AllowEmpty: Boolean = True): string;
var
  Idx: Integer; // loops thru all elements of string array
begin
  Result := '';
  for Idx := 0 to Pred(Length(Strings)) do
  begin
    if (Strings[Idx] <> '') or AllowEmpty then
      if Result = '' then
        Result := Strings[Idx]
      else
        Result := Result + Delim + Strings[Idx];
  end;
end;

LastChar

Returns the last character of the given string. It is an error if the string is empty.

function LastChar(const S: string): Char;
begin
  Result := S[Length(S)];
end;

LastPos

Finds and returns the position of the last occurence of sub string SubStr in string Str. Returns 0 if SubStr is not found.

function LastPos(const SubStr, Str: string): Integer;
var
  Idx: Integer; // an index of SubStr in Str
begin
  Result := 0;
  Idx := StrUtils.PosEx(SubStr, Str);
  if Idx = 0 then
    Exit;
  while Idx > 0 do
  begin
    Result := Idx;
    Idx := StrUtils.PosEx(SubStr, Str, Idx + 1);
  end;
end;

MultiSzToStrings

Splits out individual strings from the 'multi string' buffer MultiSz and appends each string to string list Strings. MultiSz must point to a buffer containing a sequence of #0 terminated strings followed by an additional #0 character that indicates the end of the buffer. Does nothing if either Strings or MultiSz are nil.

procedure MultiSzToStrings(const MultiSz: PChar;
  const Strings: Classes.TStrings);
var
  P: PChar;   // pointer to strings in buffer
begin
  // Do nothing in MultiSz is nil
  if not Assigned(MultiSz) then
    Exit;
  // Scan thru #0 delimited strings until #0#0 found
  P := MultiSz;
  while P^ <> #0 do
  begin
    // add string to list
    Strings.Add(P);
    // move pointer to start of next string if any
    Inc(P, SysUtils.StrLen(P) + 1);
  end;
end;

PadCenter

Centre aligns string AString within a string of size AWidth and returns the result. The string is padded as necessary with character AChar.

function PadCenter(const AString: string; const AChar: Char;
  const AWidth: Integer): string;
var
  NumPadChars: Integer; // number of padding chars required
  LPad: Integer;        // number of padding chars to left
  RPad: Integer;        // number of padding chars to right
begin
  if Length(AString) < AWidth then
  begin
    NumPadChars := AWidth - Length(AString);
    LPad := NumPadChars div 2;
    RPad := LPad;
    if Odd(NumPadChars) then
      Inc(RPad);
    Result := StringOfChar(AChar, LPad) + AString + StringOfChar(AChar, RPad);
  end
  else
    Result := AString;
end;

PadLeft

Left aligns string AString within a string of size AWidth and returns the result. The string is padded on the right as necessary with character AChar.

function PadLeft(const AString: string; const AChar: Char;
  const ALen: Integer): string;
var
  PadLength: Integer; // number of padding characters required
begin
  Result := AString;
  PadLength := ALen - Length(AString);
  if PadLength < 1 then
    Exit;
  Result := AString + StringOfChar(AChar, PadLength);
end;

PadRight

Right aligns string AString within a string of size AWidth and returns the result. The string is padded on the left as necessary with character AChar.

function PadRight(const AString: string; const AChar: Char;
  const ALen: Integer): string;
var
  PadLength: Integer; // number of padding characters required
begin
  Result := AString;
  PadLength := ALen - Length(AString);
  if PadLength < 1 then
    Exit;
  Result := StringOfChar(AChar, PadLength) + AString;
end;

ParseDelims

Returns the sub-string of string TextLine that begins at StartPos and is terminated by one of the delimiting characters from Delims or the end of the string. StartPos is updated to the index of the character after the delimiter. Returns the empty string if there is no sub-string following StartPos.

function ParseDelims(const TextLine: string; var StartPos: Integer;
  const Delims: string): string;
var
  StringEnd: Integer;     // tracks end of current string being parsed out
begin
  // Find next non-delimiter char - this is where token starts
  while (StartPos <= Length(TextLine))
    and SysUtils.IsDelimiter(Delims, TextLine, StartPos) do
    Inc(StartPos);
  // Now find next delimiter - this is where token ends
  StringEnd := StartPos;
  while (StringEnd <= Length(TextLine))
    and not SysUtils.IsDelimiter(Delims, TextLine, StringEnd) do
    Inc(StringEnd);
  // Copy result out of string
  Result := Copy(TextLine, StartPos, StringEnd - StartPos);
  StartPos := StringEnd + 1;
end;

ParseStr

Splits the string StrToParse into segments separated by Delimiter and stores each segment in turn in string list Words, replacing any existing content.

procedure ParseStr(const StrToParse: string; const Delimiter: Char; 
  const Words: Classes.TStringList);
var
  TmpInStr: string;
begin
  TmpInStr := StrToParse;
  Words.Clear;
  if Length(TmpInStr) > 0 then
  begin
    while Pos(Delimiter, TmpInStr) > 0 do
    begin
      Words.Append(Copy(TmpInStr, 1, Pos(Delimiter, TmpInStr) - 1));
      Delete(TmpInStr, 1, Pos(Delimiter, TmpInStr));
    end;
    Words.Append(TmpInStr);
  end;
end;

PosByIndex

Returns the start position of the Nth word in string Str. Words are delimited by any of the characters in Delim. Returns 0 if there is no such word.

function PosByIndex(const N: Integer; const Str: string;
  const Delims: TCharSet): Integer;
var
  En: integer; // index of end of word in AString: not used
begin
  GetStartAndEndWord(N, Str, Delims, Result, En);
end;

QuoteSpacedString

If string S contains white space it is surrounded in the quotes specified by Quote and the result is returned. If S does not contain white space it is returned unchanged.

function QuoteSpacedString(const S: string; const Quote: Char): string;
begin
  if ContainsWhiteSpace(S) then
    Result := Quote + S + Quote
  else
    Result := S;
end;

ReduceStr

Reduces the length of string S by the number of characters given by ReduceBy and returns the result.

function ReduceStr(const Str: string; ReduceBy: Integer): string;
begin
  Result := Copy(Str, 1, Length(Str) - ReduceBy);
end;

RemoveDuplicateStrings

Removes duplicate strings from the given string list. The modified string list will be sorted.

procedure RemoveDuplicateStrings(const Strings: Classes.TStrings);
var
  TempStrings: Classes.TStringList;
  Cnt: Integer;
begin
  if Strings.Count <= 1 then
    Exit;
  TempStrings := Classes.TStringList.Create;
  try
    TempStrings.Sorted := True;
    TempStrings.Duplicates := Classes.dupIgnore;
    for Cnt := 0 to Strings.Count - 1 do
      TempStrings.Add(Strings[Cnt]);
    Strings.Assign(TempStrings);
  finally
    TempStrings.Free;
  end;
end;

ReplaceWordByIndex

Replaces the Nth word from string Str with NewWord. Words are delimited by the any of the characters in Delim. Modifies Str and returns True on success. Returns False and leaves Str unchanged if there is no Nth word.

function ReplaceWordByIndex(const N: Integer; const NewWord: string;
  var Str: string; const Delims: TCharSet): Boolean;
var
  St, En: Integer;  // start and end of word to change
begin
  Result := GetStartAndEndWord(N, Str, Delims, St, En);
  if Result then
  begin
    Delete(Str, St, En - St + 1);
    Insert(NewWord, Str, St);
  end;
end;

ReverseStr

Returns the reverse of the given string.

function ReverseStr(S: string): string;
begin
  Result := SysUtils.EmptyStr;
  while System.Length(S) > 0 do
  begin
    Result := Result + StrUtils.RightStr(S, 1);
    S := StrUtils.LeftStr(S, Pred(System.Length(S)));
  end;
end;

ReverseStrR

Returns the reverse of the given string.

function ReverseStrR(const S: string): string;
begin
  if SysUtils.AnsiSameText(S, SysUtils.EmptyStr) or (System.Length(S) = 1) then
    Result := S
  else
    Result := StrUtils.RightStr(S, 1)
      + ReverseStrR(StrUtils.LeftStr(S, System.Length(S) - 1))
end;

SplitPathList (TStrings overload)

Splits PathList, which must contain semi-colon delimited file paths, into individual paths and appends each one to string list Paths.

procedure SplitPathList(const PathList: string; const Paths: Classes.TStrings);
  overload;
begin
  ExplodeStr(PathList, ';', Paths, False, True);
end;

SplitPathList (string array overload)

Splits PathList, which must contain semi-colon delimited file paths, into individual paths and returns a string array containing them.

function SplitPathList(const PathList: string): Types.TStringDynArray; overload;
begin
  Result := ExplodeStrArray(PathList, ';', False, True);
end;

SplitStr

Splits string S at the first occurence of delimiter string Delim. S1 is set to to the sub-string of S before Delim and S2 to the remainder of S after Delim. If Delim is not found then S1 is set to S and S2 to the empty string. Returns True if S contains Delim or False if not.

function SplitStr(const S, Delim: string; out S1, S2: string): Boolean;
var
  DelimPos: Integer;  // position of delimiter in source string
begin
  // Find position of first occurence of delimiter in string
  DelimPos := SysUtils.AnsiPos(Delim, S);
  if DelimPos > 0 then
  begin
    // Delimiter found: split and return True
    S1 := Copy(S, 1, DelimPos - 1);
    S2 := Copy(S, DelimPos + Length(Delim), MaxInt);
    Result := True;
  end
  else
  begin
    // Delimiter not found: return false and set S1 to whole string
    S1 := S;
    S2 := '';
    Result := False;
  end;
end;

SplitString

Splits the string AText into segments separated by Delimiter and creates and returns a string list containing the segments. The caller is responsible for freeing the returnd string list object.

function SplitString(const AText, ADelimiter: string): Classes.TStringList;
var
  LTxt, LTmp: string;
begin
  Result := TStringList.Create;
  LTxt := AText;
  while Pos(ADelimiter, LTxt) > 0 do
  begin
    LTmp := Copy(LTxt, 1, Pos(ADelimiter, LTxt) - 1);
    Result.Add(LTmp);
    LTxt := SysUtils.StringReplace(LTxt, LTmp + ADelimiter, '', []);
  end;
  if (LTxt <> '') then
    Result.Add(LTxt);
end;

StringsToMultiSz

Converts the strings from stringlist Strings into 'multi-string' format and stores the result in the buffer pointed to by MultiSz, which must be at least BufSize characters in size. Strings written to MultiSz are terminated by #0 and an additional #0 character terminates the list. Returns 0 on success or the required buffer size, in characters, if BufSize is too small or if MultiSz is nil.

function StringsToMultiSz(const Strings: Classes.TStrings;
  const MultiSz: PChar; const BufSize: Integer): Integer;
var
  ReqSize: Integer; // required buffer size
  Idx: Integer;     // loops thru Strings
  P: PChar;         // pointer into MultiSz
begin
  Result := 0;
  if not Assigned(Strings) then
    Exit;
  // Get required size of buffer
  ReqSize := 1;
  for Idx := 0 to Pred(Strings.Count) do
    Inc(ReqSize, Length(Strings[Idx]) + 1);
  if (BufSize >= ReqSize) and Assigned(MultiSz) then
  begin
    // BufSize OK and MultiSz not nil: copy string and return zero
    P := MultiSz;
    for Idx := 0 to Pred(Strings.Count) do
    begin
      // copy current string, #0 terminated
      SysUtils.StrPCopy(P, Strings[Idx]);
      // moves to next pos in buffer
      Inc(P, Length(Strings[Idx]) + 1);
    end;
    // add terminating additional #0
    P^ := #0;
  end
  else
    // BufSize too small or MultiSz is nil: return required size
    Result := ReqSize;
end;

StripAccelChars

Strips all accelerator ('&') characters from the given string and returns the resulting string.

function StripAccelChars(const S: string): string;
begin
  Result := SysUtils.StringReplace(
    S, '&', SysUtils.EmptyStr, [SysUtils.rfReplaceAll]
  );
end;

StripDuplicateStrings

Returns a string array that is a copy of given array SA with duplicates removed. The returned array will be sorted.

function StripDuplicateStrings(const SA: array of string):
  Types.TStringDynArray;
var
  SL: Classes.TStringList;
begin
  SL := Classes.TStringList.Create;
  try
    ArrayToStringList(SA, SL);
    RemoveDuplicateStrings(SL);
    Result := StringListToArray(SL);
  finally
    SL.Free;
  end;
end;

StripLastChar

Removes the last character from the string S and returns the resulting string. If S is empty then it is returned unchanged.

procedure StripLastChar(var S: string);
begin
  if Length(S) > 0 then
    Delete(S, Length(S), 1);
end;

StripWhiteSpace

Removes all white space from the given string and returns the result.

function StripWhiteSpace(const S: string): string;
var
  Idx: Integer;       // loops thru all characters in string
  ResCount: Integer;  // counts number of characters in result string
  PRes: PChar;        // pointer to characters in result string
begin
  SetLength(Result, Length(S));
  PRes := PChar(Result);
  ResCount := 0;
  Idx := 1;
  while Idx <= Length(S) do
  begin
    if (SysUtils.ByteType(S, Idx) <> mbSingleByte)
      or not IsWhiteSpace(S[Idx]) then
    begin
      PRes^ := S[Idx];
      Inc(ResCount);
      Inc(PRes);
    end;
    Inc(Idx);
  end;
  if ResCount < Length(S) then
    SetLength(Result, ResCount);
end;

StrToken

Finds and returns the first token in string S, delimited by the given separator character. The token and separator are removed from S. If no separators are found then the whole of S is returned and S is then set to the empty string.

function StrToken(var S: string; Separator: Char): string;
var
  Idx: Cardinal;  // index of Separator in S
begin
  Idx := SysUtils.AnsiPos(Separator, S);
  if Idx > 0 then
  begin
    Result := System.Copy(S, 1, Idx - 1);
    System.Delete(S, 1, Idx);
  end
  else
  begin
    Result := S;
    S := '';
  end;
end;

StrTokenCount

Counts and returns the number of tokens in string S delimited by the given separator character. Empty strings before separators are counted as tokens, but an empty string after the last separator is not.

function StrTokenCount(S: string; Seperator: Char): Integer;
begin
  Result := 0;
  while S <> '' do
  begin
    StrToken(S, Seperator);
    Inc(Result);
  end;
end;

TextWrap

Word wraps string Text, using the space character as delimiter, into lines of maximum width Width, with each line left-padded with Margin spaces. The resulting text is returned in a string with lines separated by CRLF.

function TextWrap(const Text: string; const Width, Margin: Integer): string;
var
  Word: string;               // next word in input text
  Line: string;               // current output line
  Words: Classes.TStringList; // list of words in input text
  I: Integer;                 // loops thru all words in input text

  // -------------------------------------------------------------------------
  procedure AddLine(const Line: string);
  begin
    // Adds line of text to output, offsetting line by width of margin
    if Result <> '' then    // not first line: insert new line
      Result := Result + #13#10;
    Result := Result + StringOfChar(' ', Margin) + Line;
  end;
  // -------------------------------------------------------------------------

begin
  // Get all words in text
  Words := Classes.TStringList.Create;
  try
    ExplodeStr(Text, ' ', Words);
    Result := '';
    Line := '';
    // Loop for each word in text
    for I := 0 to Pred(Words.Count) do
    begin
      Word := Words[I];
      if Length(Line) + Length(Word) + 1 <= Width then
      begin
        // Word fits on current line: add it
        if Line = '' then
          Line := Word  // 1st word on line
        else
          Line := Line + ' ' + Word;
      end
      else
      begin
        // Word doesn't fit on line
        AddLine(Line);  // output line
        Line := Word;   // store word as first on next line
      end;
    end;
    if Line <> '' then
      // Residual line after end of loop: add to output
      AddLine(Line);
  finally
    Words.Free;
  end;
end;

TitleCase

Converts the given string to title case and returns the result.

function TitleCase(const S: string): string;
var
  Idx: Integer;           // loops through each character in string
  WantCapital: Boolean;   // flag indicating whether captial letter required
begin
  Result := SysUtils.LowerCase(S);
  WantCapital := True;
  for Idx := 1 to Length(S) do
  begin
    if IsCharInSet(Result[Idx], ['a'..'z']) then
    begin
      if WantCapital then
        Result[Idx] := UpCase(Result[Idx]); // capital letter required
      WantCapital := False;                 // following chars lower case
    end
    else
      WantCapital := IsWhiteSpace(Result[Idx]); // space: next char is capital
  end;
end;

TrimChar

Trims occurrences of character C from both ends of string S and returns the result.

function TrimChar(const S: string; const C: Char): string;
begin
  Result := TrimLeftChar(TrimRightChar(S, C), C);
end;

TrimLeftChar

Trims occurrences of character C from the start of string S and returns the result.

function TrimLeftChar(const S: string; const C: Char): string;
var
  Idx: Integer; // index into string
begin
  Idx := 1;
  while (Idx <= Length(S)) and (S[Idx] = C) do
    Inc(Idx);
  if Idx > 1 then
    Result := Copy(S, Idx, MaxInt)
  else
    Result := S;
end;

TrimRightChar

Trims occurrences of character C from the end of string S and returns the result.

function TrimRightChar(const S: string; const C: Char): string;
var
  Idx: Integer; // index into string
begin
  Idx := Length(S);
  while (Idx >= 1) and (S[Idx] = C) do
    Dec(Idx);
  if Idx < Length(S) then
    Result := Copy(S, 1, Idx)
  else
    Result := S;
end;

TrimStringList

Removes lines prefixed by Prefix from string list List, updating it in place. Set Prefix to the empty string to remove empty lines, including those containing only white space.

procedure TrimStringList(const List: Classes.TStrings; const Prefix: string);
var
  I: Integer;   // loops thru each line of string list
  Line: string; // contains a line of the string list
begin
  if not Assigned(List) then
    Exit;
  I := 0;
  while I < List.Count do
  begin
    Line := SysUtils.Trim(List[I]);
    if Line = '' then
    begin
      List.Delete(I);
      Continue;
    end
    else if Prefix <> '' then
    begin
      if SysUtils.AnsiPos(Prefix, Line) = 1 then
      begin
        List.Delete(I);
        Continue;
      end;
    end;
    Inc(I);
  end;
end;

UnixLineBreaks

Converts all DOS and Mac line endings in the given string to Unix line endings and returns the result.

function UnixLineBreaks(const S: string): string;
begin
  // Replace any CRLF (MSDOS/Windows) line ends with LF
  Result := SysUtils.StringReplace(
    S, #13#10, #10, [SysUtils.rfReplaceAll]
  );
  // Replace any remaining CR (Mac) line ends with LF
  Result := SysUtils.StringReplace(
    Result, #13, #10, [SysUtils.rfReplaceAll]
  );
end;

WordCount

Returns the number of white space delimited words in the given string.

function WordCount(S: string): Integer;
begin
  S := SysUtils.Trim(S);
  if S <> '' then
    Result := CountDelims(CompressWhiteSpace(S), ' ') + 1
  else
    Result := 0;
end;

View the whole database.

Go to the DelphiDabbler website.