1. Home
  2. /
  3. Docs
  4. /
  5. Articles Report Writer
  6. /
  7. Report Functions
  8. /
  9. String Functions

String Functions

String functions are available throughout the Articles report script editor and can be used in band event handlers, script procedures, and inline expressions enclosed in square brackets within text objects.


Chr / Ord

Chr converts an integer ASCII code to its corresponding character. Ord does the reverse โ€” converting a character to its ASCII code. Useful for inserting special characters such as tabs and line breaks, or for checking whether a character falls within a particular range.

Chr(I: Integer): Char
Ord(Ch: Char): Integer
ParameterTypeDescription
IIntegerASCII code to convert to a character (Chr)
ChCharCharacter to convert to an ASCII code (Ord)
// Insert a tab character between two values (useful in TSV export scripts)
Result := [Customer.Name] + Chr(9) + [Customer.Phone];

// Insert a Windows line break into a multi-line value
Result := 'Line one' + Chr(13) + Chr(10) + 'Line two';

// Check whether the first character of a code is a letter A-Z
var firstChar := [Item.Code][1];
if (Ord(firstChar) >= Ord('A')) and (Ord(firstChar) <= Ord('Z')) then
  Result := 'Alpha code'
else
  Result := 'Numeric code';

CompareText

Compares two strings without regard to case. Returns 0 if equal, a negative number if the first string is less, and a positive number if it is greater. Use this for case-insensitive comparisons without needing to call Lowercase on both sides first.

CompareText(S1: String; S2: String): Integer
ParameterTypeDescription
S1StringThe first string
S2StringThe second string to compare against

Returns 0 if equal, negative if S1 < S2, positive if S1 > S2.

// 'ACTIVE', 'Active', and 'active' all match
if CompareText([Customer.Status], 'active') = 0 then
  Result := 'Current Customer'
else
  Result := 'Inactive';

// Check for one of several status values
var status := [Orders.Status];
if (CompareText(status, 'shipped') = 0) or
   (CompareText(status, 'delivered') = 0) then
  Result := 'Fulfilled'
else
  Result := 'Pending';

// Alphabetical range check
if CompareText([Customer.Name], 'M') < 0 then
  Result := 'A - L'
else
  Result := 'M - Z';

Copy

Extracts a substring starting at a given position for a given number of characters. Positions are 1-based โ€” the first character is at position 1. Copy and MidStr do the same thing; use whichever name you prefer.

Copy(S: String; From: Integer; Count: Integer): String
ParameterTypeDescription
SStringThe source string
FromIntegerStarting position (1 = first character)
CountIntegerNumber of characters to extract
Result := Copy('Hello World', 7, 5);
// Returns: 'World'

// Extract the year from a stored date code 'YYYYMMDD'
Result := Copy([Period.Code], 1, 4);
// '20240315' returns '2024'

// Extract the month portion
Result := Copy([Period.Code], 5, 2);
// '20240315' returns '03'

// Extract everything after a known 3-character prefix 'GL-'
var s := [Account.Code];
Result := Copy(s, 4, Length(s) - 3);
// 'GL-1200' returns '1200'

Delete

Removes a specified number of characters from a string in place, starting at a given position. Because Delete modifies the variable directly, you must assign the field value to a local variable first โ€” you cannot pass a field expression directly.

procedure Delete(var S: String; From: Integer; Count: Integer)
ParameterTypeDescription
SStringThe string variable to modify (must be a variable, not a field expression)
FromIntegerStarting position of the characters to remove (1-based)
CountIntegerNumber of characters to remove
// Remove the '+1' country code from a stored phone number
var phone := [Customer.Phone];
if Copy(phone, 1, 2) = '+1' then
  Delete(phone, 1, 2);
Result := phone;
// '+15551234567' becomes '5551234567'

// Strip the 'INV-' prefix from a reference number
var ref := [Invoice.Reference];
if Copy(ref, 1, 4) = 'INV-' then
  Delete(ref, 1, 4);
Result := ref;
// 'INV-001234' becomes '001234'

// Remove a trailing asterisk flag character
var code := [Item.Code];
if RightStr(code, 1) = '*' then
  Delete(code, Length(code), 1);
Result := code;

Insert

Inserts one string into another at a specified position, modifying the target variable in place. As with Delete, assign the field value to a local variable before calling Insert. Positions are 1-based.

procedure Insert(S: String; var S2: String; Pos: Integer)
ParameterTypeDescription
SStringThe string to insert
S2StringThe target string variable to insert into
PosIntegerPosition at which to insert (1-based)
// Format a 9-digit EIN '123456789' as '12-3456789'
var ein := [Company.EIN];
Insert('-', ein, 3);
Result := ein;

// Format a 10-digit phone '5551234567' as '555-1234567'
var phone := [Customer.Phone];
Insert('-', phone, 4);
Result := phone;

// Insert a space between a numeric prefix and the rest of a code
// '12ABCD' becomes '12 ABCD'
var s := [Item.Code];
Insert(' ', s, 3);
Result := s;

LeftStr

Returns the leftmost N characters of a string. If the string is shorter than N, the full string is returned unchanged.

LeftStr(S: String; N: Integer): String
ParameterTypeDescription
SStringThe source string
NIntegerNumber of characters to return from the left
// Truncate a description to 30 characters for a narrow column
Result := LeftStr([Item.Description], 30);

// Build a 3-letter code from the start of a customer name
Result := LeftStr(Uppercase([Customer.Name]), 3);
// 'Acme Corp' becomes 'ACM'

// Truncate with ellipsis only when the text exceeds the limit
var s := [Orders.Notes];
if Length(s) > 40 then
  Result := LeftStr(s, 40) + '...'
else
  Result := s;

Length

Returns the number of characters in a string. Returns 0 for an empty string.

Length(S: String): Integer
ParameterTypeDescription
SStringThe string to measure
// Check whether a notes field has any content
if Length(TrimSafe([Orders.Notes])) > 0 then
  Result := [Orders.Notes]
else
  Result := '(No notes)';

// Truncate with ellipsis only when needed
var s := [Item.Description];
if Length(s) > 50 then
  Result := LeftStr(s, 50) + '...'
else
  Result := s;

// Validate that a phone number has enough digits
if Length(CleanNumber([Customer.Phone])) < 10 then
  Result := 'Invalid phone number'
else
  Result := FormatPhone([Customer.Phone]);

Lowercase

Converts all characters in a string to lowercase. See also Uppercase.

Lowercase(S: String): String
ParameterTypeDescription
SStringThe string to convert
// Case-insensitive comparison
if Lowercase([Customer.Status]) = 'active' then
  Result := 'Current Customer';

// Normalise mixed-case data before applying NameCase
Result := NameCase(Lowercase([Customer.Name]));
// Works correctly whether input is 'JOHN SMITH' or 'john smith'

// Use before UpperFirst to normalise then sentence-capitalise
Result := UpperFirst(Lowercase([Orders.Notes]));
// 'APPROVED BY MANAGER' becomes 'Approved by manager'

MidStr

Returns a substring starting at a specified position for a given number of characters. Positions are 1-basedMidStr and Copy do the same thing; use whichever name you prefer.

MidStr(S: String; Start: Integer; Count: Integer): String
ParameterTypeDescription
SStringThe source string
StartIntegerStarting position (1 = first character)
CountIntegerNumber of characters to extract
// Extract area code from a stored 10-digit number '5551234567'
Result := MidStr([Customer.Phone], 1, 3);
// Returns: 555

// Extract the exchange portion (digits 4-6)
Result := MidStr([Customer.Phone], 4, 3);
// Returns: 123

// Extract a date portion from a reference number 'INV-20240315-001'
Result := MidStr('INV-20240315-001', 5, 8);
// Returns: 20240315

// Extract a 2-character state code from a combined field 'FL-Miami'
Result := MidStr([Location.Code], 1, 2);
// Returns: FL

NameCase

Converts a string to proper name casing โ€” the first letter of each word is uppercased and the remainder are lowercased. Use this to clean up names stored in all-caps in older databases. See also UpperFirst for single-word sentence capitalisation.

NameCase(S: String): String
ParameterTypeDescription
SStringThe string to convert
Result := NameCase('JOHN SMITH');
// Returns: 'John Smith'

Result := NameCase('acme manufacturing co');
// Returns: 'Acme Manufacturing Co'

// For robust normalisation of mixed-case data, lowercase first
Result := NameCase(Lowercase([Customer.Name]));
// Handles 'JOHN SMITH', 'john smith', and 'jOhN sMiTh' all correctly

PadLeft

Pads a string on the left with a specified character until it reaches the desired total length. If the string is already at or beyond that length, it is returned unchanged. Most commonly used to zero-pad numeric codes for sorting or fixed-width export.

PadLeft(S: String; Len: Integer; Ch: Char): String
ParameterTypeDescription
SStringThe string to pad
LenIntegerThe total desired length of the result
ChCharThe character to pad with (e.g. '0' or ' ')
// Zero-pad an invoice number to 6 digits
Result := PadLeft(IntToStr([Invoice.InvoiceNumber]), 6, '0');
// 1234 becomes '001234'
// 99   becomes '000099'

// Right-align a code in a 15-character space-padded field
Result := PadLeft([Item.Code], 15, ' ');

// Pad a check number to 8 digits for a fixed-width bank export
Result := PadLeft(IntToStr([Check.Number]), 8, '0');
// 5 becomes '00000005'

PadRight

Pads a string on the right with a specified character until it reaches the desired total length. Use this to left-align text in fixed-width columns or to create visual leader lines and separators.

PadRight(S: String; Len: Integer; Ch: Char): String
ParameterTypeDescription
SStringThe string to pad
LenIntegerThe total desired length of the result
ChCharThe character to pad with
// Left-align a product name in a 30-character export field
Result := PadRight([Item.Name], 30, ' ');

// Create a dotted leader line between a label and a value
Result := PadRight('Subtotal', 25, '.');
// Returns: 'Subtotal.................'

// Build a fixed-width text line combining padded columns
Result := PadRight([Customer.Name], 30, ' ') +
          PadLeft(FormatCurrencySafe([Orders.Total]), 12, ' ');

// Create a full divider line
Result := PadRight('', 40, '-');
// Returns: '----------------------------------------'

Pos

Returns the character position of the first occurrence of a substring within a string. Returns 0 if not found. Positions are 1-based. Commonly used to detect whether a string contains a keyword, or to locate a delimiter so the string can be split.

Pos(SubStr: String; S: String): Integer
ParameterTypeDescription
SubStrStringThe substring to search for
SStringThe string to search within
// Check if a note contains the word 'URGENT'
if Pos('URGENT', Uppercase([Orders.Notes])) > 0 then
  Result := 'Priority Order'
else
  Result := 'Normal';

// Split a combined 'FL-Miami' field on the hyphen
var code := [Location.Code];
var p    := Pos('-', code);
if p > 0 then
begin
  var stateCode := Copy(code, 1, p - 1);
  var cityName  := Copy(code, p + 1, Length(code));
  Result := cityName + ' (' + stateCode + ')';
  // Returns: 'Miami (FL)'
end;

// Basic email format check
var email := [Customer.Email];
if (Pos('@', email) > 0) and (Pos('.', email) > 0) then
  Result := email
else
  Result := '(invalid email)';

RightStr

Returns the rightmost N characters of a string. Commonly used to extract the last digits of account or reference numbers, or the extension portion of a ZIP+4 code.

RightStr(S: String; N: Integer): String
ParameterTypeDescription
SStringThe source string
NIntegerNumber of characters to return from the right
// Mask an account number, showing only the last 4 digits
Result := '****' + RightStr([Account.Number], 4);
// Returns: ****7890

// Extract the 4-digit extension from a ZIP+4 field '12345-6789'
Result := RightStr([Customer.Zip], 4);
// Returns: 6789

// Remove a trailing flag character safely
var code := [Item.Code];
if RightStr(code, 1) = '*' then
  Result := LeftStr(code, Length(code) - 1)
else
  Result := code;

SetLength

Resizes a string variable to a specified number of characters. If the new length is shorter, the string is truncated from the right. If longer, it is extended with null characters (#0). Most commonly used to pre-allocate a string buffer in procedures that build strings character by character.

Note: For simple truncation, LeftStr is the better choice. SetLength pads with null characters when extending, which can cause unexpected output in some export formats.

procedure SetLength(var S: String; L: Integer)
ParameterTypeDescription
SStringThe string variable to resize
LIntegerThe new length in characters
// Pre-allocate a fixed-length buffer before filling it character by character
var buffer: String;
SetLength(buffer, 80);
// buffer is now exactly 80 characters wide, filled with #0

// Truncate a local variable to 20 characters
var s := [Item.Description];
SetLength(s, 20);
Result := s;
// If s is shorter than 20 it will be padded with #0 โ€” use LeftStr to avoid this

Trim

Removes leading and trailing whitespace (spaces and tabs) from a string. Use TrimSafe instead if the value might be Null.

Trim(S: String): String
ParameterTypeDescription
SStringThe string to trim
Result := Trim('  Hello World  ');
// Returns: 'Hello World'

// Clean a field before concatenating
Result := Trim([Customer.City]) + ', ' + Trim([Customer.State]);

// Trim before a length check
if Length(Trim([Orders.Notes])) = 0 then
  Result := '(No notes)'
else
  Result := Trim([Orders.Notes]);

TrimSafe

Removes leading and trailing whitespace from a string. Unlike TrimTrimSafe handles Null and empty variant values without raising an error, making it the safer choice when working with database fields that may be null.

TrimSafe(S: String): String
ParameterTypeDescription
SStringThe string to trim. Null and empty values are handled safely.
// Safe to call on a field that might be NULL โ€” no error raised
Result := TrimSafe([Vendor.Address2]);

// Trim before comparing
if TrimSafe([Item.Code]) = 'DISC' then
  Result := 'Discontinued'
else
  Result := TrimSafe([Item.Description]);

// Use in an inline text object expression where nulls are possible
// [TrimSafe([Orders.Notes])]

Uppercase

Converts all characters in a string to uppercase. See also Lowercase.

Uppercase(S: String): String
ParameterTypeDescription
SStringThe string to convert
// Force an account code to uppercase for consistent display
Result := Uppercase([Account.Code]);
// 'sales-west' becomes 'SALES-WEST'

// Use before Pos for a case-insensitive keyword search
if Pos('HOLD', Uppercase([Orders.Notes])) > 0 then
  Result := 'On Hold';

// Build a short code from the first 3 letters of a name
Result := LeftStr(Uppercase([Customer.Name]), 3);
// 'Acme Corp' becomes 'ACM'

UpperFirst

Converts only the first character of a string to uppercase, leaving all other characters unchanged. This gives sentence-style capitalisation. It differs from NameCase, which capitalises the first letter of every word.

UpperFirst(S: String): String
ParameterTypeDescription
SStringThe string to process
// Capitalise the first letter of a note or comment field
Result := UpperFirst([Orders.Notes]);
// 'approved by manager' becomes 'Approved by manager'

// Normalise before applying โ€” lowercase first, then capitalise
Result := UpperFirst(Lowercase([Customer.Name]));
// 'JOHN SMITH' becomes 'John SMITH'
// Use NameCase if you want 'John Smith'

// Use in a greeting line
Result := 'Dear ' + UpperFirst(Lowercase([Contact.FirstName])) + ',';

// Capitalise a status value stored in lowercase
Result := UpperFirst([Orders.Status]);
// 'pending' becomes 'Pending'