Ex 0003
Ex 0003
In other words, a string invariably has elements ranging from the result of the Low
function to that of the High function applied to the same string. If you want to know,
in general, which is the active compiler setting, you can use:
Low (string)
This returns either 0 or 1 depending on the active option. In any case, always keep in
mind that this is just a local compiler setting that determines how the index within
square brackets is interpreted.
note A string is just a string, and the concept of a zero-based string is completely wrong. The data
structure in memory is not different in any way, so you can pass any string to any function that
uses a notation with any base value, and there is no problem at all. In other words, if you have a
code fragment accessing to strings with a zero-based notation you can pass the string to a function
that is compiled using the settings for a one-based notation.
Concatenating Strings
I have already mentioned that unlike other languages, Object Pascal has full support
for direct string concatenation, which is actually a rather fast operation. In this
chapter I'll just show you some string concatenations code, while doing some speed
testing. Later on, in Chapter 18, I'll briefly cover the TStringBuilder class, which
follows the .NET notation for assembling a string out of different fragments. While
there are reasons to use TStringBuilder, performance is not the most relevant one
(as the following example will show).
So, how do we concatenate strings in Object Pascal? Simply by using the + operator:
var
str1, str2: string;
begin
str1 := 'Hello,';
str2 := ' world';
str1 := str1 + str2;
Notice how I used the str1 variable both on the left and on the right of the assign-
ment, adding some more content to an existing string rather than assigning to a
brand new one. Both operations are possible, but adding content to an existing
string is where you can get some nice performance.
This type of concatenation can be also done in a loop, like the following extracted
from the LargeString application project:
uses
Diagnostics;
const
var
str1, str2: string;
I: Integer;
t1: TStopwatch;
begin
str1 := 'Marco ';
str2 := 'Cantu ';
t1 := TStopwatch.StartNew;
for I := 1 to MaxLoop do
str1 := str1 + str2;
t1.Stop;
Show('Length: ' + str1.Length.ToString);
Show('Concatenation: ' + t1.ElapsedMilliseconds.ToString);
end;
By running this code, I get the following timing on a Windows virtual machines and
on an Android device (the computer is quite a bit faster):
// Windows (in a VM)
Length: 12000006
Concatenation: 59
// Android (Nexus 4)
Length: 12000006
Concatenation: 991
The application project has also similar code based on the TStringBuilder class.
While I don't want to get to the details of that code (again, I'll describe the class in
Chapter 18) I want to share the actual timing, for comparison with the plain concate-
nation timing just displayed
// Windows (in a VM)
Length: 12000006
StringBuilder: 79
// Android (Nexus 4)
Length: 12000006
StringBuilder: 1057
As you can see, concatenation can be safely considered the fastest option.
I've logically grouped the string helper operations (most of which have many over-
loaded versions), shortly describing what they do, considering that quite often that
their names are rather intuitive:
• Copy or partial copy operations like Copy, CopyTo, Join, and SubString
• String modification operations like Insert, Remove, and Replace
• For conversion from various data types to string, you can use Parse and Format
• Conversion to various data types, when possible can be achieved using
ToBoolean, ToInteger, ToSingle, ToDouble, and ToExtended while you can turn
a string into an array of characters with ToCharArray
• Fill a string white space or specific characters with PadLeft, PadRight, and one of
the overloaded versions of Create. At the opposite, you can remove white space
at one end of the string or both using TrimRight, TrimLeft, and Trim
• String comparison and equality test (Compare, CompareOrdinal, CompareText,
CompareTo, and Equals)—but keep in mind you can also, to some extent, use the
equality operator and the comparison operators
• Changing case with LowerCase and UpperCase, ToLower and ToUpper, and ToUp-
perInvariant
• Test the string content with operations like Contains, StartsWith, EndsWith.
Search in the string can be done using IndexOf for finding the position of a given
character (from the beginning or from a given location), the similar IndexOfAny
(which looks for one of the elements of an array of characters), the LastIndexOf
and LastIndexOfAny operations which work backwards from the end of the
string, and the special purpose operations IsDelimiter and LastDelimiter
• Access to general information about the string with functions like Length, which
returns the number of characters, CountChars, which also takes surrogate pairs
into account, GetHashCode, which returns a hash of the string, and the various
tests for “emptiness” which include IsEmpty, IsNullOrEmpty, and IsNullOr-
WhiteSpace
• String special operations like Split, which breaks a string into multiple ones
based on a specific character, and removing or adding quotes around the string
with QuotedString and DeQuoted
• And, finally, access to individual characters with Chars[], which has the numeri-
cal index of the element of the string among square brackets. This can be used
only for reading a value (not for changing it) and uses a zero-based index like all
other string helper operations.
It is important to notice, in fact, that all of the string helper methods have been build
following the string convention used by many other languages, which includes the
concept that string elements start with zero and go up to the length of the string
minus one. In other words, all string helper operations use zero-based indexes as
parameters and return values.
note The Split operation is relatively new to the Object Pascal RTL. A previously common approach
was loading a string in a string list, after setting a specific line separator, and later access the indi-
vidual strings, or lines. The Split operation is significantly more efficient and flexible.
Given the large amount of operations you can apply directly to strings, I could have
created several projects demonstrating these capabilities. Instead, I'll stick to a few
relatively simple operations, albeit very common ones.
The StringHelperTest application project has two buttons. In each of them the first
part of the code builds and displays a string:
var
Str1, Str2: string;
I, NIndex: Integer;
begin
Str1 := '';
// create string
for I := 1 to 10 do
Str1 := Str1 + 'Object ';
// count occurrences
I := -1;
NCount := 0;
repeat
I := Str1.IndexOf('O', I + 1); // search from next element
if I >= 0 then