progress-4gl

Strings

Introduction#

In Progress ABL there are two types of strings, those defined as CHARACTER and those defined as LONGCHAR. A file larger than 32K in length is a LONGCHAR. Most strings are unless specified any other way case insensitive.

Remarks#

Remember - all positions start with the position 1!

Defining, assing and displaying a string

Generally you should always define all variable and parameters as NO-UNDO unless you really need to.

DEFINE VARIABLE cString AS CHARACTER   NO-UNDO.

cString = "HELLO".

DISPLAY cString.

Concatenating strings

Using the + operator you can easily concatenate two or more strings.

DEFINE VARIABLE cString AS CHARACTER   NO-UNDO.

cString = "HELLO".

cString = cString + " " + "GOODBYE".

DISPLAY cString FORMAT "X(20)".

String manipulation

There are a couple of useful built in functions for working with string. All functions working with the position of characters start with index 1 as the first character, not 0 as is common in many languages.

STRING - converts any value to a string

This example converts the integer 2000 to the string “2000”.

DEFINE VARIABLE i AS INTEGER     NO-UNDO.
DEFINE VARIABLE c AS CHARACTER   NO-UNDO.

i = 2000.

c = STRING(i).

DISPLAY c.

CHR and ASC - converts single characters to and from ascii.

CHR(integer)

Returns the character representation for ascii code integer

ASC(character)

Returns the ascii integer value for the character

DEFINE VARIABLE ix     AS INTEGER   NO-UNDO.
DEFINE VARIABLE letter AS CHARACTER NO-UNDO FORMAT "X(1)" EXTENT 26.

DO ix = 1 TO 26:
  letter[ix] = CHR((ASC("A")) - 1 + ix).
END.

DISPLAY SKIP(1) letter WITH 2 COLUMNS NO-LABELS
  TITLE "T H E  A L P H A B E T".

LENGTH - returns the length of a string

LENGTH(string). //Returns an integer with the length of the string.

DEFINE VARIABLE cString AS CHARACTER   NO-UNDO.

cString = "HELLO".

MESSAGE "The string " cString " is " LENGTH(cString) " characters long" VIEW-AS ALERT-BOX. 

SUBSTRING - returns or assigns a part of a string

  • SUBSTRING(string, starting-position, length).

Returns “length” characters from “string” starting on position “starting-position”.

  • SUBSTRING(string, starting-position).

Returns the rest of “string”, starting at position “starting-position”

DEFINE VARIABLE cString AS CHARACTER   NO-UNDO.

cString = "ABCDEFGH".

DISPLAY SUBSTRING(cString, 4, 2). //Displays "DE" 
DISPLAY SUBSTRING(cString, 4). //Displays "DEFGH"

Substring can also be used to overwrite a part of a string. Use the same syntax but assign that substring instead:

DEFINE VARIABLE cString AS CHARACTER   NO-UNDO.

cString = "ABCDEFGH".
 
SUBSTRING(cString, 4, 2) = "XY". //Replaces position 4 and 5 with "XY" 

DISPLAY cString.  

There’s also a similar function called OVERLAY this example from the Progress documentation covers the differences between OVERLAYand SUBSTRING:

/* This procedure illustrates the differences between the SUBSTRING and
   OVERLAY statements. */
DEFINE VARIABLE cOriginal  AS CHARACTER NO-UNDO INITIAL "OpenEdge".
DEFINE VARIABLE cSubstring AS CHARACTER NO-UNDO.
DEFINE VARIABLE cOverlay   AS CHARACTER NO-UNDO.
DEFINE VARIABLE cResults   AS CHARACTER NO-UNDO.

/* Default behavior without optional LENGTH. */
ASSIGN
 cSubstring              = cOriginal
 SUBSTRING(cSubstring,2) = "***"
 cOverlay                = cOriginal
 OVERLAY(cOverlay,2)     = "***"
 cResults                = "target = ~"OpenEdge~". ~n~n" 
  + "If you do not supply a length, SUBSTRING and OVERLAY default as follows:
  ~n~n" + "SUBSTRING(target,2) = ~"***~"  yields:  " + cSubstring + ". ~n" 
  + "OVERLAY(target,2)     = ~"***~"  yields:  " + cOverlay + ".".

/* Behavior with zero LENGTH. */
ASSIGN
 cSubstring                = cOriginal
 SUBSTRING(cSubstring,2,0) = "***"
 cOverlay                  = cOriginal
 OVERLAY(cOverlay,2,0)     = "***"
 cResults                  = cResults + "~n~n" 
  + "For a zero length, SUBSTRING and OVERLAY behave as follows:  ~n~n" 
  + "SUBSTRING(target,2,0) = ~"***~"  yields:  " + cSubstring + ". ~n" 
  + "OVERLAY(target,2,0)     = ~"***~"  yields:  " + cOverlay + ".".

/* Behavior with LENGTH < replacement. */
ASSIGN 
 cSubstring                = cOriginal
 SUBSTRING(cSubstring,2,1) = "***"
 cOverlay                  = cOriginal
 OVERLAY(cOverlay,2,1)     = "***"
 cResults                  = cResults + "~n~n" 
  + "For a length shorter than the replacement, SUBSTRING and OVERLAY behave
  as follows: ~n~n" + "SUBSTRING(target,2,1) = ~"***~"  yields:  " 
  + cSubstring + ". ~n" + "OVERLAY(target,2,1)     = ~"***~"  yields:  " 
  + cOverlay + ".".

/* Behavior with LENGTH = replacement. */
ASSIGN 
 cSubstring                = cOriginal
 SUBSTRING(cSubstring,2,3) = "***"
 cOverlay                  = cOriginal
 OVERLAY(cOverlay,2,3)     = "***"
 cResults                  = cResults + "~n~n" 
  + "For a length equal to the replacement, SUBSTRING and OVERLAY behave as
  follows:  ~n~n" + "SUBSTRING(target,2,3) = ~"***~"  yields:  " 
  + cSubstring + ". ~n" + "OVERLAY(target,2,3)     = ~"***~"  yields:  " 
  + cOverlay + ".".

/* Behavior with LENGTH > replacement. */
ASSIGN 
 cSubstring                = cOriginal
 SUBSTRING(cSubstring,2,6) = "***"
 cOverlay                  = cOriginal
 OVERLAY(cOverlay,2,6)     = "***"
 cResults                  = cResults + "~n~n" 
  + "For a length greater than the replacement, SUBSTRING and OVERLAY behave
  as follows:  ~n~n" + "SUBSTRING(target,2,6) = ~"***~"  yields:  " 
  + cSubstring + ". ~n" + "OVERLAY(target,2,6)     = ~"***~"  yields:  " 
  + cOverlay + ".".

MESSAGE cResults VIEW-AS ALERT-BOX.

INDEX - return the position of a string in a string.

R-INDEX will to the same thing but search right to left.

INDEX(source, target)

Search target within source (left to right) and return it’s position. If it’s missing return 0.

INDEX(source, target, starting-position).

Same as above but start searching at starting-position

DEFINE VARIABLE str AS CHARACTER   NO-UNDO.

str = "ABCDEFGH".

DISPLAY INDEX(str, "cd") INDEX(str, "cd", 4). //Will display 3 and 0

REPLACE - replaces a string within a string.

REPLACE(string, from-string, to-string)

Replaces from-string with to-string in string. From-string and to-string don’t need to be of the same length, to-string can also be nothing ("") to remove a character.

DEFINE VARIABLE c AS CHARACTER   NO-UNDO.

c = "ELLO".

DISPLAY REPLACE(c, "E", "HE"). // Displays "HELLO"

c = "ABABABA".

DISPLAY REPLACE(c, "B", ""). // Remove all Bs

TRIM - removes leading and trailing whitespaces (or other characters).

This can be useful when cleaning up indata.

TRIM(string)

Removes all leading and trailing spaces, tabs, line feeds, carriage returns.

TRIM(string, character).

Removes all leading and trailing “characters”.

LEFT-TRIM and RIGHT-TRIM does the same thing but only leading or trailing.

DEFINE VARIABLE c AS CHARACTER   NO-UNDO.

c = "__HELLO_WORLD_____".

DISPLAY TRIM(c, "_").
/*Displays HELLO_WORLD without all the leading and 
trailing underscores but leaves the one in the middle.
REPLACE would have removed that one as well */

SUBSTITUTE - substitutes paramters in a string.

SUBSTITUTE is a limited function for replacing up to nine preformatted parameters in a string.

SUBSTITUTE(string, param1, param2, …, param9).

The parameters must be in the format &1 to &9.

If you want to use an ampersand in the string (and not use it as a parameter) escape it with another ampersand: &&.

DEFINE VARIABLE str AS CHARACTER   NO-UNDO.
                                      
str = "&1 made &2 goals in &3 games playing for &4".

MESSAGE SUBSTITUTE(str, "Zlatan Ibrahimovic", 113, 122, "Paris Saint-Germain") VIEW-AS ALERT-BOX.
MESSAGE SUBSTITUTE(str, "Mats Sundin", 555, 1305, "Toronto Maple Leafs") VIEW-AS ALERT-BOX.

A parameter can appear more than once in a string, all will be replaced:

MESSAGE SUBSTITUTE("&1 &2 or not &1 &2", "To", "Be") VIEW-AS ALERT-BOX.

CASE-SENSITIVE strings

All strings in Progress ABL are case sensitive unless specified otherwise.

This example will display a message box saying that the strings are identical.

DEFINE VARIABLE str1 AS CHARACTER   NO-UNDO.
DEFINE VARIABLE str2 AS CHARACTER   NO-UNDO.

str1 = "abc".
str2 = "ABC".

IF str1 = str2 THEN 
    MESSAGE "The strings are identical" VIEW-AS ALERT-BOX.

To declare a string case sensitive you just add the attribute CASE-SENSITIVE

DEFINE VARIABLE str1 AS CHARACTER   NO-UNDO CASE-SENSITIVE.
DEFINE VARIABLE str2 AS CHARACTER   NO-UNDO.

str1 = "abc".
str2 = "ABC".

IF str1 = str2 THEN 
    MESSAGE "The strings are identical" VIEW-AS ALERT-BOX.
ELSE 
    MESSAGE "There's a difference" VIEW-AS ALERT-BOX.

(It’s enough that one of the strings has it in this case).

BEGINS and MATCHES

BEGINS - returns TRUE if one string begins with another string.

string1 BEGINS string2

If string1 BEGINS with (or is equal to) string2 this will return true. Otherwise it will return false. If string two is empty ("") it will always return true.

BEGINS is very useful in queries where you want to search the beginning of something, for instance a name. But it’s basically a function working on strings.

DEFINE VARIABLE str AS CHARACTER   NO-UNDO.
DEFINE VARIABLE beg AS CHARACTER   NO-UNDO.

str = "HELLO".
beg = "HELLO".
DISPLAY str BEGINS beg. // yes

str = "HELLO".
beg = "H".
DISPLAY str BEGINS beg. // yes

str = "HELLO".
beg = "".
DISPLAY str BEGINS beg. // yes


str = "HELLO".
beg = "HELLO WORLD".
DISPLAY str BEGINS beg. // no

MATCHES returns true if certain wildcard critera is met in a string.

string1 MATCHES expression

Returns true if string1 matches the wildcard expression:

* (asterisk) = 0 to n characters (basically any string of any length)

. (period) = wildcard for any character (except null)

DEFINE VARIABLE str AS CHARACTER   NO-UNDO.
DEFINE VARIABLE beg AS CHARACTER   NO-UNDO.

str = "HELLO".
beg = "HELLO".
DISPLAY str MATCHES beg. // yes

str = "HELLO".
beg = "H*".
DISPLAY str MATCHES beg. // yes

str = "HELLO".
beg = "*O".
DISPLAY str MATCHES beg. // yes

str = "HELLO WORLD".
beg = "HELLO.WORLD".
DISPLAY str MATCHES beg. // yes

str = "HELLO WORLD".
beg = "*WORL..".
DISPLAY str MATCHES beg. // no

str = "*HELLO WORLD".
beg = "WOR*LD".
DISPLAY str MATCHES beg. // no

Converting upper and lower case

As mentioned before strings are normally case insensitive but that only regards comparison of strings. There’s built in functions for changing case.

CAPS (string)

Makes string upper case

LC(string)

Makes string lower case

DEFINE VARIABLE c AS CHARACTER   NO-UNDO.
DEFINE VARIABLE d AS CHARACTER   NO-UNDO.

c = "Hello".
d = "World".

DISPLAY CAPS(c) LC(d). // HELLO world

Remember strings normally are case insensitive

DEFINE VARIABLE c AS CHARACTER   NO-UNDO.
DEFINE VARIABLE d AS CHARACTER   NO-UNDO.

c = "hello".
d = "hello".

DISPLAY CAPS(c) = LC(d). // yes

Unless specificed as CASE-SENSITIVE

DEFINE VARIABLE c AS CHARACTER   NO-UNDO CASE-SENSITIVE.
DEFINE VARIABLE d AS CHARACTER   NO-UNDO.

c = "hello".
d = "hello".

DISPLAY CAPS(c) = LC(d). // no

Lists

There are a number of functions and methods for working with comma (or other character) separated lists in Progress 4GL.

NUM-ENTRIES Returns the number of entries in a list. You can optionally specify delimiter, comma is default

NUM-ENTRIES(string [, delimiter])

Using comma, the default delimiter:

DEFINE VARIABLE cList AS CHARACTER   NO-UNDO.

cList = "Goodbye,cruel,world!".

DISPLAY NUM-ENTRIES(cList). //3

Using another delimiter, semilcolon:

DEFINE VARIABLE cList AS CHARACTER   NO-UNDO.

cList = "Goodbye;cruel;world!".

DISPLAY NUM-ENTRIES(cList, ";"). //3

ENTRY - function - returns a specified entry in a list

As usual starting position is 1, not 0!

ENTRY( entry, list [, delimiter]).

DEFINE VARIABLE cList AS CHARACTER   NO-UNDO.

cList = "Goodbye,cruel,world!".

DISPLAY ENTRY(2, cList). //cruel

ENTRY - method - assigning the value of a specified entry in a list

ENTRY( entry, list [, delimiter]) = value

DEFINE VARIABLE cList AS CHARACTER   NO-UNDO.

cList = "Goodbye,cruel,world!".

ENTRY(1, cList) = "Hello".
ENTRY(2, cList) = "nice".

MESSAGE REPLACE(cList, ",", " ") VIEW-AS ALERT-BOX. //Hello nice world!

LOOKUP - check a list for a specific entry. Returns it’s entry.

If the string isn’t present in the list lookup will returns 0

LOOKUP(string, list [, delimiter])

DEFINE VARIABLE cList AS CHARACTER   NO-UNDO.

cList = "Hello,nice,world!".

MESSAGE LOOKUP("nice", cList) VIEW-AS ALERT-BOX. //2
MESSAGE LOOKUP("cruel", cList) VIEW-AS ALERT-BOX. //0

Special characters (and escaping)

In Progress 4GL the normal way to write a special character is to preceed it with a tilde character (~).

These are the default special characters

Sequence Interpreted as Comment
~” Used to write ” inside strings defined using “string”.
~’ Used to write ’ inside strings defined using ‘string’.
~~ ~ For instance if you want to print the sequence and not how its interpreted.
~\ \
~{ { { is used in preprocessors and sometimes escaping is needed.
~nnn A single character nnn is an octal number representing the ascii value of the character.
~t tab
~n New line/line feed
~r Carriage return
~E Escape
~b Backspace
~f Form feed

If you want to display tilde at all it must be escaped!

MESSAGE "A single tilde: ~~" VIEW-AS ALERT-BOX.

MESSAGE "At sign: ~100" SKIP
        "Tab~tseparated~twords!" SKIP
        "A linefeed:~n"
        "Escaping a quote sign: ~"This is a quote!~"" SKIP VIEW-AS ALERT-BOX.

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow