Chapter 15

Text Manipulation

True magic is the study of the higher truths of Nature.
--Gustavus Miller, What's in a Dream

Text strings are an important part of almost any world. You have already seen one powerful method for constructing text with embedded arguments and formatting macros. There are a number of other elementary instructions for working with text. These are described in the following sections.

1. findtext

The findtext instruction searches inside one text string for another. This operation is not case-sensitive, but the findText instruction is. There are several other instruction pairs that follow this pattern: the one containing an upper case letter is case sensitive.

findtext (T1,T2,Start=1,End=0)
findText (T1,T2,Start=1,End=0)
T1 is the text in which to search.
T2 is the text to find.
Start is the starting position.
End is position at which to stop.
Returns the first position found.

Positions in a text string are just like an array: they range from 1 to the last character of the text string. If the specified search text is not found, 0 is returned. Notice that 0 is also used as the default value for the position at which to stop searching, indicating that there is no such position. By default, therefore, the entire text string is searched.

One example of a use for findtext() is to scan conversational text for keywords.

mob/rat
   verb/tell(msg as text)
      set src in oview()
      if(findtext(msg,"cheese"))
         view() << "[src] looks at [usr] hopefully."
         walk_to(src,usr)

2. copytext

The copytext instruction extracts a piece of another text string. This instruction, and the preceding findtext, are meant to mimic the `copy' and `find' operations of a standard text editor.

copytext (Txt,Start=1,End=0)
Txt is the text string.
Start is the starting position.
End is the position at which to stop.
Returns the piece as a new text string.

3. addtext

The addtext instruction combines two or more text strings and returns the result. This can also be done by embedding each text value one after the other in another text string, but when there are many such values to combine, it is sometimes easier to use addtext(). Yet another method of concatenation is to use the + operator.

addtext (Txt1,Txt2,...)
Returns one combined text string.

4. lentext

The lentext instruction reports the number of characters in the text string.

lentext (Txt)
Txt is the text to measure.
Returns the number of characters.

5. Text Conversions

There are several instructions for converting text from one form to another. These are described in the following sections.

5.1 uppertext

The uppertext instruction converts any lowercase characters to uppercase.

uppertext (Txt)
Txt is the text to convert.
Returns the new uppercase text string.

5.2 lowertext

The lowertext instruction converts any uppercase characters to lowercase.

lowertext (Txt)
Txt is the text to convert.
Returns the new lowercase text string.

5.3 text2num

The text2num instruction converts a text string to a numerical value. If the text is not a number, null is returned.

text2num (Txt)
Txt is the text to convert.
Returns the corresponding number.

It is important to realize that a text value is fundamentally different from a numerical value even though they may appear the same in output. If you try to perform numerical operations on a text string, they will not work as expected because all text strings and other non-numerical objects are treated as 0 in this context. The text must first be converted to a number with text2num before the value can be manipulated in this way.

5.4 num2text

The num2text instruction is the inverse of text2num. It converts a numerical value to text. This can also be done by embedding the numeric expression in a text string, but some additional control over how the number is formatted is provided by num2text().

num2text (Num,SigDigs)
Num is the number to convert.
SigDigs is the number of significant digits.
Returns the new text string.

The number of significant digits determines when scientific notation will be used. In embedded text expressions, numbers are given 6 significant digits by default, so scientific notation will only be used for numbers with more than nine digits. If you want a different result, you can explicitly use num2text().

6. Comparing Text Strings

The simplest method for comparing two text values is to test for equality of the references to those data objects using the == operator. Identical text strings are always combined into one data object to conserve memory. Exact comparison of text values is therefore simply a matter of comparing references.

There are several special instructions for comparing text strings when an exact comparison is not desired. For example, you may not want case sensitivity in the comparison or you may want to know the alphabetical order of the text values.

6.1 cmptext

The cmptext instruction performs a case-insensitive comparison of text strings.

cmptext (Txt1,Txt2,...)
Txt1 is the first text string to compare.
Txt2 is the second text string to compare.
Returns 1 if equal and 0 if not.

6.2 sorttext

The sorttext instruction is used to determine the alphabetical order of text strings. It is not case sensitive, but sortText provides the same functionality with case sensitivity.

sorttext (Txt1,Txt2,...)
sortText (Txt1,Txt2,...)
Txt1 is the first text string to compare.
Txt2 is the second text string to compare.
Returns 1 if in ascending order, -1 if descending, otherwise 0.

The following example displays an alphabetical list of players.

proc/SortTextList(lst[])
   var/i
   var/j
   for(i=1,i<=lst.len,i++)
      for(j=i+1,j<=lst.len,j++)
         if(sorttext(lst[i],lst[j]) == -1) //swap positions
            var/tmp = lst[i]
            lst[i] = lst[j]
            lst[j] = tmp

mob/verb/who()
   var/lst[0]
   var/mob/M
   var/N
   for(M)
      if(M.client) lst += M.name
   SortTextList(lst)
   for(N in lst) usr << N

7. Text Documents

A text string in DM is enclosed in single quotes. This is intended for short items consisting of a few words. Longer compositions may instead be entered as text documents. These are the same as text strings except they begin with {"} and end with "
html
.

Whereas both newlines and double quotes must be escaped in a text string, they may be directly inserted into a text document. This may help produce more legible source code when generating multiple lines of output in a single statement.

The following example uses a text document to display a login banner.

mob/Login()
   . = ..()
   usr << {"

The Great BYOND
Welcome, [usr]. I am glad you could join us. Please refrain from scribbling on the walls. "}

Lengthy documents should usually be placed in a separate file. However, as in this example, messages containing embedded expressions can be neatly handled with an inline text document.