Using Strings in Maple
Introduction
A string in Maple is an atomic object. (The type atomic describes numbers, strings, symbols, and indexed names.) For most purposes, it is a single, nearly indivisible unit that stands for itself. Substrings within a string can be accessed in various ways; however, a string is not mutable.
A string constant is written as zero or more characters enclosed in double quotation marks ("). The sequence of characters between the quotation marks make up the string. Characters are taken literally, except when they are preceded by backslashes (\):
If a backslash character is encountered, the next character is examined to determine the character that will become part of the string:
Syntax Resulting string character \a ASCII bell character (BEL, byte value 7) \b ASCII backspace character (BS, byte value 8) \e ASCII escape character (ESC, byte value 27) \f ASCII form-feed character (FF, byte value 12) \n ASCII line-feed character (LF, byte value 10) \r ASCII carriage return character (CR, byte value 13) \t ASCII tab character (HT, byte value 9) \v ASCII vertical tab character (VT, byte value 11) \\ a backslash character \" a double quotation mark (same as typing "")
If a newline follows a backslash, the backslash and the newline are both ignored. Any other character following a backslash is taken literally, and the backslash is ignored (that is, "\x" is the same as "x").
As shown in the table above, a double quotation mark can be inserted in a string by prefixing it with a backslash. Alternatively, a double quotation mark can be inserted by typing two consecutive double quotation marks. This is analogous to the way back-quotes can be inserted into Maple names.
The following gives examples of how string constants are written, and the characters that appear in the resulting strings:
restart;
printf( "%s\n", "Hello" );
Hello
printf( "%s\n", "He said, ""Don't""." );
He said, "Don't".
printf( "%s\n", "\"Quotes\"" );
"Quotes"
printf( "%s\n", "abc\ndef" );
abc
def
A string has no value other than itself. It cannot be assigned a value, nor will it ever evaluate to anything other than itself.
In the grammar of the Maple language, a string may appear anywhere that a name may appear. String quotes have the same binding strength as name quotes.
Printing of Strings (and Names)
Both the line-printer and the pretty-printer actually print strings with their enclosing double quotation marks, in a format that can be parsed by Maple to give the same string. When a double quotation mark appears within a string, it is printed as a backslash followed by the quotation mark, instead of as a pair of quotation marks.
"Short"; lprint(%);
Short
"Short"
"A Bit Longer"; lprint(%);
A Bit Longer
"A Bit Longer"
To print a string with no quotation marks (for example, to print a message to the user), use the printf function from the Maple I/O library instead.
printf("Please press spacebar to continue...\n");
Please press spacebar to continue...
Operations on Entire Strings
This section describes the operations that can be performed on strings as atomic objects.
String Comparisons
Strings can be compared using the Maple relational operators.
Testing for the equality or inequality of two strings is a very low-cost operation, because only one copy of any given string exists, and only the addresses of the strings have to be compared:
evalb("foo" = "bar");
false
evalb("foo" <> "bar");
true
evalb("foo" = "foo");
evalb("foo" <> "foo");
Strings can also be compared lexicographically, using the operators <, <=, >, >=. In this case, the actual characters of the strings are compared. Individual characters are compared using the collating sequence of the character set of the underlying architecture. Note that uppercase and lowercase alphabetic characters are distinct. (In ASCII, all the uppercase characters are considered to be "less than" the lowercase characters; that is, "A" < "Z" < "a" < "z".)
evalb("foo" < "bar");
evalb("foo" <= "bar");
evalb("bar" < "foo");
evalb("foo" <= "foo");
For backward compatibility, the Maple lexorder function can also be used. The call lexorder(A, B) for strings A and B is equivalent to evalb(a <= b).
lexorder("bar","foo");
lexorder("foo","bar");
lexorder("foo","foo");
String Sorting
The built-in functions sort, min, and max also work with strings.
The sort function will take a list of strings, and return a sorted list of the same strings.
sort(["carrot","apple","zucchini","banana","pear","Orange"]);
Orange,apple,banana,carrot,pear,zucchini
The sort function can also mix strings and names when sorting, provided that none of the names evaluate to anything other than strings or names.
sort(["carrot",apple,"zucchini",banana,pear,"Orange"]);
The max and min functions will return, respectively, the lexicographically greatest and the lexicographically least of their string arguments.
max("carrot","apple","zucchini","banana","pear","Orange");
zucchini
min("carrot","apple","zucchini","banana","pear","Orange");
Orange
String Concatenation
The concatenation function cat is used to form concatenations of strings, as well as names (and other objects). Strings and names can be mixed in a concatenation operation. The type of the result will be a string or a name, depending on whether the type of the left-hand side is a string or name.
cat("a","b");
ab
cat("a",b);
cat(a,"b");
cat(a,b);
With cat, ranges of characters can be used. A character is a string of length 1. A range of characters refers to all the characters in the underlying character set, beginning with the first character in the range, and ending with the last character in the range.
cat(a,"a".."f");
aa,ab,ac,ad,ae,af
cat("b","x".."z",1..3);
bx1,bx2,bx3,by1,by2,by3,bz1,bz2,bz3
Interactively (or at parse time), concatenated string constants can be formed by juxtaposition.
"abc"
"de";
abcde
Iteration over a Range of Characters
Ranges of characters, as described in the previous section, can also be used to form sequences through the seq function and the dollar operator ($). In either case, an expression is evaluated for each character in the specified range.
seq(i,i="a".."f");
a,b,c,d,e,f
$"a".."f";
The Maple for statement can also be used to iterate over a range of characters, but this must be done by using from and to, and not an actual range. When using for with characters, both the from and the to parts must be specified; unlike the set of integers, most character sets are finite. The by part may also be specified; if it is, it must be an integer.
for c from "a" to "f" do c od;
a
b
c
d
e
f
for c from "z" to "a" by -5 do c od;
z
u
p
k
Conversions
A string can be converted to a name by using convert( string, name ).
convert( "This was a string", 'name' );
This was a string
Likewise, a name can be converted to a string by using convert( name, string ).
convert( `This was a name`, 'string' );
This was a name
The latter operation is not often necessary, because most functions that expect a string will also accept a name. Only when some obscure functionality is required, such as iterating over the characters within a name, is this conversion explicitly needed.
A string containing an expression or a statement expressed in Maple syntax can be converted to an actual expression or be executed as an actual statement by using the parse function. This function accepts both strings and names.
parse( "sqrt(x^2+y^2)" );
x2+y2
parse( "for c from \"a\" to \"c\" do c od", statement );
Attributes
Strings can be assigned attributes in the same way that names can. Maple has two ways of assigning attributes to objects. Some objects, such as lists, result in a new object when attributes are assigned. Others, such as names and procedures, simply attach the attributes to the existing object. Strings fall into the latter category. Multiple identical strings with different attributes cannot exist. Attributes are applied to a string with the setattribute function.
setattribute( "foo", 'red' );
foo
setattribute( `foo`, 'blue' );
attributes("foo");
red
attributes(`foo`);
blue
convert( `foo`, 'string' );
attributes(%);
convert( "foo", 'name' );
Operations on the Characters Within a String
This section describes operations that treat strings as compound objects.
Subscripting
One or more characters within a string may be extracted using subscripting, in much the same way that members of a list can be extracted. The rules that apply to string subscripts are the same as those for lists, except that a string subscript is allowed to exceed the length of the string.
S := "This is a string";
S ≔ This is a string
S[1..4];
This
S[-6..-1];
string
S[-6..-1][4..5];
in
S[2..10000];
his is a string
The existing substring function performs the same operation as string subscripting, except that it will also work with names.
N := `This is a name`;
N ≔ This is a name
N[1..4];
This is a name1..4
substring(S,1..4);
substring(N,1..4);
The op and subsop functions do not work with strings. Strings are atomic, and implementing op and subsop to work within strings would be inconsistent with this type of object.
Iteration over the Characters within a String
Just as it is possible to iterate over a range of characters (single character strings), it is possible to iterate over the characters appearing within a string, one character at a time.
The seq function will evaluate an expression for each character within a string, and produce an expression sequence of the results.
seq( i, i="A string" );
A, ,s,t,r,i,n,g
Likewise, the for statement can be used with the in clause to loop over the characters within a string.
for c in "A string" do c od;
A
s
t
r
i
n
g
Functions That Take Strings Instead of Names
Functions and statements that require a file name accept names or strings as the file name. These include: writeto, appendto, and the read and save statements. Any of the I/O library functions that can accept a file name (for example, fopen, fprintf, and so on) accept strings as well.
X := 1/2;
X ≔ 12
#save X,"X.m";
Note: The special file names terminal and default are still names. Passing them as strings will result in Maple trying to access actual files with the names "terminal" and "default".
Many of the I/O library functions used to require names where strings would have been more appropriate (if they had existed). For example, the printf for these arguments:
printf( "%a is approximately equal to %g\n", 1/3, evalf(1/3) );
1/3 is approximately equal to 0.333333
I/O library functions, such as readline, return strings instead of names.
#readline(terminal);
The debugger function stoperror accepts a string specifying the error message on which to stop.
stoperror("division by zero");
division by zero
The searchtext and SearchText functions work on strings as well as names.
searchtext( "world", "Hello, world!" );
8
The convert call converts either a name or string to a list of integers, and converts a list of integers to a string instead of a name.
convert( `A name`, 'bytes' );
65,32,110,97,109,101
convert( %, 'bytes' );
A name
Sample Application
The following Maple procedure reads a file, and counts the number of occurrences of each lowercase letter within the file.
CountLower := proc( fileName::string ) local f, # File descriptor line, # Line being processed c, # Character being processed counts; # Table of character counts # Clear the table of character counts. for c from "a" to "z" do counts[c] := 0 end do; # Open the file and read the first line. f := fopen(fileName,READ); line := readline(f); # For each line, count up the characters. while line <> 0 do for c in line do if c >= "a" and c <= "z" then counts[c] := counts[c] + 1 end if end do; line := readline(f) end do; fclose(f); # Display a table of the counts. for c from "a" to "z" do printf("\t\"%s\" %5d\n",c,counts[c]); end do; NULL end proc:
For example, take the file
simpleDocument := cat(kernelopts(datadir), "/help/XMLTools/SimpleDocument.dtd"):
CountLower(simpleDocument);
"a" 7
"b" 3
"c" 8
"d" 6
"e" 20
"f" 5
"g" 1
"h" 4
"i" 18
"j" 0
"k" 0
"l" 7
"m" 9
"n" 11
"o" 10
"p" 7
"q" 0
"r" 7
"s" 5
"t" 15
"u" 6
"v" 0
"w" 0
"x" 0
"y" 3
"z" 0
See also the StringTools package for a collection of routines optimized for manipulating text.
Return to Index for Example Worksheets.
Download Help Document