Delphi has a large number of utility procedures and functions that work with strings. This chapter only illustrates the most frequently used procedures and functions. They are:
function Pos(Substr: string; S: string): Integer;
function Copy(S; Index, Count: Integer): string;
function Length(S): Integer;
function IntToStr(Value: Integer): string; overload;
function StrToInt(const S: string): Integer;
procedure Delete(var S: string; Index, Count:Integer);
procedure Insert(Source: string; var S: string; Index: Integer);
procedure Val(S; var V; var Code: Integer);
procedure Str(X [: Width [: Decimals ]]; var S);
String searching can be implemented manually or with the Pos function. The Pos function returns 0 if the substring cannot be found in the string. The following example uses the Pos function to determine if a string contains more than one word.
Listing 6-12: Searching a string with the Pos function
program Project1; {$APPTYPE CONSOLE} uses SysUtils; var s: string; begin Write('Enter some text: '); ReadLn(s); if Pos(' ', s) <> 0 then WriteLn('You entered a couple of words.') else WriteLn('You entered only one word.'); ReadLn; end.
If you only need to search for a single character in a string, you can also implement your own Pos function. The following function returns the index of the character in the string if the character is found or 0 if the character doesn't exist.
Listing 6-13: Manual character searching
program Project1; {$APPTYPE CONSOLE} uses SysUtils; function CharPos(ch: Char; const s: string): Integer; var i: Integer; begin Result := 0; if s <> '' then begin for i := 1 to Length(s) do begin if s[i] = ch then begin Result := i; Exit; end; // if s[i] end; // for i end; // if s end; var testStr: string; iPos: Integer; begin testStr := 'BorlaNd Delphi'; iPos := CharPos('N', testStr); if iPos <> 0 thenTimes New Roman testStr[iPos] := 'n'; WriteLn(testStr); { Borland Delphi } ReadLn; end.
The Insert procedure accepts three parameters. The first parameter is the string value that is to be inserted into another string, the second parameter is the destination string, and the last parameter is the index at which the string is to be inserted.
The following example uses the Insert procedure to properly format a string that contains a poorly formatted uses list. The string contains a comma-delimited list of Delphi units, but there are no spaces between the commas and the unit names. The Insert procedure is used to insert spaces after each comma in the string.
Listing 6-14: Using the Insert procedure
program Project1; {$APPTYPE CONSOLE} uses SysUtils; var Units: string; i: Integer; begin Units := 'Windows,SysUtils,Forms,StdCtrls,Controls,Classes;'; i := 0; repeat Inc(i); if Units[i] = ',' then begin Insert(' ', Units, i + 1); Inc(i); end; // if Units[i] until i = Length(Units); WriteLn(Units); ReadLn; end.
We can't use the for loop here because we change the length of the string inside the loop. If you use the for loop, all spaces will be added before or after the first comma. This happens because the for loop only reads the string length at the beginning of the loop. Since both repeat-until and while loops always reevaluate the condition, you can try to write a while loop version of this example.
The Delete procedure enables you to delete a certain number of characters from a string. The Delete procedure accepts three parameters: a variable string parameter that is modified, the index where deletion should start, and the number of characters to be deleted.
The following example uses the Delete procedure to remove all spaces from a string. The RemoveSpaces procedure calls the Delete procedure as long as there are spaces in the source string. The parameter must be a variable parameter because that is the only parameter type that allows you to make changes to the original variable.
Listing 6-15: Using the Delete procedure
program Project1; {$APPTYPE CONSOLE} uses SysUtils; procedure RemoveSpaces(var s: string); var spacePos: Integer; begin spacePos := Pos(' ', s); while spacePos <> 0 do begin Delete(s, spacePos, 1); spacePos := Pos(' ', s); end; end; var testStr: string; begin testStr := ' D el p h i '; RemoveSpaces(testStr); WriteLn(testStr); { Delphi } ReadLn; end.
The Copy function accepts three parameters. The first parameter is the source string, the second parameter is the index where the copying starts, and the last parameter defines how many characters are copied.
The following example shows how to use the Copy function to extract the drive and directory portions of a file name.
Listing 6-16: Using the Copy function
program Project1; {$APPTYPE CONSOLE} uses SysUtils; function GetFilePath(const AFileName: string): string; var i: Integer; begin i := Length(AFileName); while i > 0 do begin if AFileName[i] = '\' then Break; Dec(i); end; // while if i > 1 then Result := Copy(AFileName, 1, i) else Result := ''; end; var testStr: string; begin testStr := 'c:\windows\system32\kernel32.dll'; WriteLn(GetFilePath(testStr)); { c:\windows\system32\ } ReadLn; end.
This version of the GetFilePath function only works on the Windows operating system because we only search for a backslash. This function doesn't work on Linux because Linux uses slashes to separate directories.
If you know for sure that a function or procedure is specific to a platform and you want to be completely professional, you should mark that procedure or function with the platform directive:
function GetFilePath(const AFileName: string): string; platform;
When you mark a procedure or a function with the platform directive, you will always receive a compiler warning that the specified function or procedure is specific to a platform.
In this case, it's really easy to make the function platform independent. The SysUtils unit contains a global constant that holds the proper delimiter for each platform:
const PathDelim = {$IFDEF MSWINDOWS} '\'; {$ELSE} '/'; {$ENDIF}
All we need to do to make the GetFilePath function platform independent is to change the if-then statement in the loop:
while i > 0 do begin if AFileName[i] = PathDelim then Break; Dec(i); end; // while
Probably the most frequent of all conversions is the conversion between the string and integer data types. The common way to do these conversions is to use the IntToStr and StrToInt functions declared in the SysUtils unit. These functions are easy to use and really fast.
var sValue: string; iValue: Integer; begin sValue := IntToStr(2005); iValue := StrToInt('-24'); end.
If you're trying to create a really small application, you'll probably remove the SysUtils unit from the uses list. In this case, you can use the Str and Val procedures that are declared in the System unit.
var sValue: string; iValue: Integer; begin iValue := 42; Str(iValue, sValue); { sValue = '42' } end.
The Val procedure accepts three parameters: the string value that needs to be converted to an integer, the destination integer variable, and the error code parameter. If the Val procedure fails to convert the string to an integer, the variable passed as the last parameter will hold the index of the character that cannot be converted.
var sValue: string; iValue: Integer; code: Integer; begin sValue := '-250'; Val(sValue, iValue, code); if code <> 0 then begin WriteLn('Character ', code, ' is invalid.'); ReadLn; end; end.