Table of Contents

4.6 Working with Strings

By manipulating strings we can program anything, from a user-input validator to a word-scramble game. With a little ingenuity, we can make neat visual text effects, text tickers, and other fun stuff.

We can manipulate strings with both operators and built-in functions. String operators can join multiple strings together or compare the characters of two strings. Built-in functions can examine a string's properties and contents, extract a portion of a string, check a character's code point, create a character from a code point, change the case of the characters in a string, and even turn a string into a variable or property name.

4.6.1 Joining Strings Together

Joining strings together (creating a new string from two or more strings) is called concatenation. As we've seen, we can concatenate two strings with the plus operator (+), like this:

"Macromedia" + "Flash"

This line of code yields the single string value "MacromediaFlash". Oops! We forgot to put a space between the words. To add the space, we can insert it within the quotes that define one of the strings, such as:

"Macromedia " + "Flash"  // Yields "Macromedia Flash"

But that's not always practical. In most cases, we don't want to add a space to a company or a product name. So instead, we join three strings together, the middle one of which is simply an empty space:

"Macromedia" + " " + "Flash"   // Also yields "Macromedia Flash"

Note that the space character is not the same as the empty string we discussed earlier, because the empty string has no characters between the quotes.

Ordinarily, you wouldn't concatenate literal strings, because you could more easily write the result as one string�"Macromedia Flash"�in the first place. As a more realistic example, we can concatenate variables that contain string data. Consider the following code:

var company = "Macromedia";
var product = "Flash";
// Set the variable sectionTitle to "Macromedia Flash"
var sectionTitle = company + " " + product;

In lines 1 and 2, we store string values in variables. Then, we join these values together with a space. Two of our string values are contained in variables, and one (the space) is a string literal. This is not a problem; it happens all the time.

Occasionally, we'll want to append characters onto an existing string. For example, we can create a custom welcome message for a web site like this:

// Hard-code the userName for this example. 
// (Normally it would be retrieved via an input text field or from a database.)
var userName = "Karsten";
var greeting = "Welcome to GreatSite.com";  // Our welcome message
greeting = greeting + " " + userName;       // Add user's name to welcome message

This gets the job done, but notice that we have to refer to greeting twice in line 2. To be more efficient, we can use the += operator, which appends the string on its right to the string variable on the left:

var greeting = "Welcome to GreatSite.com";  // Our welcome message
greeting += (" " + username);               // Add user's name to welcome message

You may encounter the deprecated Flash 4 string concatenation operators & and add when examining legacy code. The + operator should be used in Flash 5 and later. See Appendix C for more information on backward compatibility.

4.6.1.1 The concat( ) function

The concat( ) function appends characters to a string, similar to +=. Because concat( ) is a function, it uses the dot operator, like this:

var product = "Macromedia".concat(" Flash");
var sentence = "How are you";
var question = sentence.concat("?")

Take heed, though�unlike +=, the concat( ) function does not alter the string that it is applied to; it merely returns the concatenated string value. In order to make use of that value, we must assign it to a variable or other data container. Study the following code closely, so you'll understand the difference between += and concat( ):

// Here we mistakenly forget to store the return of concat( ) in a variable.
var userName = "Karsten";
var greeting = "Welcome to GreatSite.com";
greeting.concat(userName);
trace(greeting);  // Displays "Welcome to GreatSite.com"
                  // The value of greeting was unaffected by concat( )
// Here we properly store the return of concat( ) in a variable.
finalGreeting = greeting.concat(" " + userName);

The concat( ) function also accepts multiple arguments (that is, it can combine multiple comma-separated strings into one string):

var userName = "Karsten";
// Sets finalGreeting to "Welcome to GreatSite.com, Karsten!"
finalGreeting = greeting.concat(" ", username, "!");

This code is the same as:

finalGreeting = greeting;
finalGreeting += " " + userName + "!";

4.6.2 Comparing Strings

To check whether two strings are the same, we use the equality (= =) and inequality (!=) operators. We often compare strings when executing code based on a condition. For example, if a user enters a password, we need to compare his input string with the actual password. The result of our comparison governs the behavior of our code, such as whether to grant access to the password-restricted functionality.

4.6.2.1 Using the equality (= =) and inequality (!=) operators

The equality operator takes two operands�one on its left and one on its right. For string comparisons, the operands can be string literals or any variable, array element, object property, or expression that can be converted to a string:

"hello" =  = "goodbye"       // Compare two string literals
userGuess =  = "fat-cheeks"  // Compare a variable with a string
userGuess =  = password      // Compare two variables

Although Flash 4 used different operators for its string and nonstring comparisons, in Flash 5 and later, the = = and != operators can also be used to compare numbers and other datatypes (see Appendix C). We limit the discussion here to strings. If the operand on the right has the exact same characters in the exact same order as the operand on the left, the two strings are considered equal, and the result is the Boolean value true.

Two individual characters in ActionScript are considered equal only if they have the same Unicode code point. This means that upper- and lowercase letters (which have different code points) are not considered equal. Likewise, letters with and without diacritical marks, such as ü and u, have different code points and are not considered equal. Furthermore, ActionScript does not consider any multiglyph character sequences to be equal to the corresponding single-glyph character. For example, n~ is not considered equal to ñ (though the two might be considered equal in other languages).

The following comparisons all evaluate to false:

"olive-orange" =  = "olive orange"  // Not equal
"nighttime" =  = "night time"       // Not equal
"Day 1" =  = "day 1"                // Not equal
"n~" =  = "ñ"                       // Not equal
"ü" =  = "u"                        // Not equal

Because string comparisons result in the Boolean value true or false, we can use them as test expressions within conditional statements and loops, like this:

if (userGuess =  = password) {
  this.gotoAndStop("classifiedContent");
} else {
  this.gotoAndStop("entryFailed"); 
}

If the expression (userGuess = = password) is true, then the this.gotoAndStop("classifiedContent"); statement will be executed. If the expression is false, the classified content is skipped, and the user is sent to a frame where an error message is displayed.

We'll learn more about Boolean values later in this chapter, and we'll learn about conditional statements in Chapter 7.

To check whether two strings are not equal, we use the inequality operator, which yields a result opposite to the equality operator. For example, the following expressions represent the values false and true, respectively:

"Jane" != "Jane"  // false, because the two strings are equal
"Jane" != "Biz"   // true, because the strings are different

Here we use the inequality operator to take some action only if two strings are not equal:

if (userGender != "boy") {
  // Girls-only code goes here...
}

You may encounter the deprecated eq and ne operators, used for string equality and inequality comparisons in Flash 4, when examining legacy code. The = = and != operators should be used in Flash 5 and later. See Chapter 5 for coverage of the strict equality and strict inequality operators, which test equality without performing automatic datatype conversion.

4.6.2.2 Character order and alphabetic comparisons

We can also compare two strings on a character-order basis. We saw earlier that each character has a numeric code point assigned to it and that these code points are ordered numerically in a character set (in ActionScript's case, that character set is Unicode). We can check which character comes first in the order using the comparison operators: greater than (>), greater than or equal to (>=), less than (<), and less than or equal to (<=). Each comparison operator compares two operands:

"a" < "b"      // true
"2" > "&"      // true
"r" <= "R"     // false
"$" >= "@"     // false

Much like equality and inequality expressions, comparison expressions yield a Boolean value, true or false, depending on the relationship of the operands. Each operand can be anything that yields a string value. The comparison operators can also be used to compare other datatypes, such as numbers, but we limit our discussion here to string operands.

Since the characters A to Z and a to z are grouped in alphabetic sequence in both Unicode and Latin 1, we frequently use character-order comparisons to determine which of two letters comes first alphabetically in the Latin alphabet. Note, however, that all uppercase letters come before all lowercase letters in the Latin 1 character set. If we forget this, we're in for some surprising results:

"Z" < "a"       // Evaluates to true
"z" < "a"       // Evaluates to false
"Cow" < "bird"  // Evaluates to true

ActionScript does not use the Unicode Collation Algorithm (UCA) when sorting characters; characters are compared on a strict code-point basis. The UCA outlines the rules for comparing international characters using regional alphabetization and accounting for case, diacritical marks, and multicharacter sequences. For more information, see:

http://www.unicode.org/unicode/reports/tr10

Here's a closer look at each comparison operator; in the following descriptions, the comparison character is defined as the first nonidentical character found in the two operands:

Greater than (>)

Yields true if the comparison character of the left operand appears later in the Unicode character order than the comparison character of the right operand. If the two operands are identical, > returns false:

"b" > "a"      // true
"a" > "b"      // false
"ab" > "ac"    // false (the second character is the comparison character)
"abc" > "abc"  // false (the strings are identical)
"ab" > "a"     // true (b is the comparison character)
"A" > "a"      // false ("A" comes before "a" in the character order)
Greater than or equal to (>=)

Yields true if the comparison character of the left operand appears later in the character order than the comparison character of the right operand or if the two operands are identical:

"b" >= "a"  // true
"b" >= "b"  // true
"b" >= "c"  // false
"A" >= "a"  // false ("A" and "a" occupy different code points)
Less than (<)

Yields true if the comparison character of the left operand appears earlier in the Unicode character order than the comparison character of the right operand. If the two operands are identical, < returns false:

"a" < "b"      // true
"b" < "a"      // false
"az" < "aa"    // false (the second character is the comparison character)
Less than or equal to (<=)

Yields true if the comparison character of the left operand appears earlier in the character order than the comparison character of the right operand or if the two operands are identical:

"a" <= "b"  // true
"a" <= "a"  // true
"z" <= "a"  // false

To determine which of two nonalphabetic characters comes first in the Latin 1 character order (which follows the Unicode order), consult Appendix B. To determine the Unicode code point for any character, see http://www.unicode.org/charts.

The following example checks whether a character is a letter from the Latin alphabet (as opposed to a number, punctuation mark, or other symbol):

var theChar = "w";
if ((theChar >= "A" && theChar <= "Z") || (theChar >= "a" && theChar <= "z")) {
  trace("The character is in the Latin alphabet.");
}

Notice how the logical OR operator (||) lets us check two conditions at once. We'll study OR in Chapter 5.

You may encounter the deprecated gt, ge, lt, and le operators, used for string comparison in Flash 4, when examining legacy code. The >, >=, <, and <= operators should be used in Flash 5 and later.

4.6.3 Using Built-in String Functions

With the exception of the concat( ) function, every tool we've used with strings so far has been an operator. Now we'll see how to use built-in functions and properties to perform more advanced string manipulation.

To execute a built-in function on a string, we must perform a function call, which takes the form:

string.functionName(arguments)

For example, here we execute the charAt( ) function on myString:

myString.charAt(2)

Many string functions return a new string derived from the original string. We assign these return values to variables or object properties for future use, such as:

thirdCharacter = myString.charAt(2);

4.6.4 Character Indexing

Many of the string functions make use of a character's index�its numeric position relative to the string's first character, starting at 0, not 1. The first character is numbered 0, the second is numbered 1, the third is numbered 2, and so on. For example, in the string "red", the r is at index 0, the e is at index 1, and the d is at index 2.

Using character indexes we identify portions of a string. We may, for example, instruct the interpreter to "Get the characters from index 3 to index 7," or we may ask it, "What character is at index 5?"

4.6.5 Examining Strings

We can inspect and search within strings using the built-in length property or the charAt( ), indexOf( ) , and lastIndexOf( ) functions.

4.6.5.1 The length property

The length property tells us how many characters are in a string. Because it is a property, not a function, we don't use parentheses or arguments when referring to it (the older Flash 4 length( ) function was deprecated in Flash 5). Here we see the length of several strings:

"Flash".length         // length is 5
"skip intro".length    // length is 10 (spaces count as characters)
"".length              // The empty string contains 0 characters
var axiom = "all that glisters will one day be obsolete";
axiom.length           // 42

Because character indexes start at 0 (i.e., they are zero-relative), the index of the last character is always equal to the length of the string minus one.

A string's length property can be read but not set. We can't make a string longer by doing this:

axiom.length = 100;  // Nice try, but it ain't gonna work
4.6.5.2 The charAt( ) function

We can determine the character at any index within a string using the charAt( ) function, which takes the form:

string.charAt(index)

where string may be any literal string value or an identifier that contains a string; index is an integer, or an expression that resolves to an integer, that indicates the position of the character we want to retrieve. The value of index should be between 0 and string.length - 1. If index does not fall in that range, the empty string is returned. Here are some examples:

"It is 10:34 pm".charAt(1)  // Returns "t", the second character
var country = "Canada";  
country.charAt(2);          // Returns "n", the third character
var x = 4;  
fifthLetter = country.charAt(x);                  // fifthLetter is "d"
lastLetter = country.charAt(country.length - 1);  // lastLetter is "a"
4.6.5.3 The indexOf( ) function

We use the indexOf( ) function to search for characters in a string. If the string we're searching contains our search sequence, indexOf( ) returns the index (i.e., position) of the sequence's first occurrence in the string. Otherwise, it returns the value -1. The general form of indexOf( ) is:

string.indexOf(character_sequence, start_index)

where string is any literal string value or an identifier that contains a string; character_sequence is the string for which we're searching, which may be a string literal or an identifier that contains a string; and start_index is the zero-relative starting position of the search. If start_index is omitted, the search starts at the beginning of string.

Let's use indexOf( ) to check whether a string contains the character W:

"GWEN!".indexOf("W");  // Returns 1

Yup, W is the second character in "GWEN!", so we get 1, the index of the W character. Remember, character indexes start at 0, so the second character's index is 1.

What happens if we search for the lowercase character w? Let's see:

"GWEN!".indexOf("w");  // Returns -1

There is no w in "GWEN!", so indexOf( ) returns -1. The upper- and lowercase versions of a letter are different characters, and indexOf( ) is case sensitive!

Now let's make sure that there's an @ sign in an email address:

var email = "daniella2dancethenightaway.ca";  // Oops, someone forgot to press Shift!
// If there's no @ sign, warn the user via the formStatus_txt text field
if (email.indexOf("@") =  = -1) {
  formStatus_txt.text = "The email address is not valid.";
}

We don't have to limit our searches to single characters. We can also search for an entire character sequence in a string. Let's look for "Canada" in the address of a company:

var iceAddress = "St. Clair Avenue, Toronto, Ontario, Canada";
iceAddress.indexOf("Canada");  // Returns 36, the index of the "C" in "Canada"

Notice that indexOf( ) returns the position of the first character in "Canada". Now let's compare the return value of iceAddress.indexOf("Canada") to -1, and assign the result to a variable that stores the nationality of the company:

var isCanadian = iceAddress.indexOf("Canada") != -1;

The value of iceAddress.indexOf("Canada") != -1 will be true if iceAddress.indexOf("Canada") does not equal -1 (if "Canada" is found) and false if iceAddress.indexOf("Canada") does equal -1 (if "Canada" is not found). We then assign that Boolean value to the variable isCanadian, which we can use to create a country-specific mailing form for North America:

if (isCanadian) {
  mailDesc = "Please enter your postal code.";
} else {
  mailDesc = "Please enter your ZIP code.";
}

The indexOf( ) function can also help us determine which part of a string we need to extract. We'll see how that works when we learn about the substring( ) function.

4.6.5.4 The lastIndexOf( ) Function

We just saw that the indexOf( ) function returns the location of a character sequence's first occurrence in a string. The lastIndexOf( ) function returns the location of a character sequence's last occurrence in a string, or -1 if the sequence isn't found. The general form of lastIndexOf( ) is just like that of indexOf( ):

string.lastIndexOf(character_sequence, start_index)

The only difference is that since lastIndexOf( ) searches a string backward, start_index refers to the rightmost character we want included in our search (not the leftmost). If start_index is omitted, it defaults to string.length - 1 (the last character in the string).

For example:

paradox = "pain is pleasure, pleasure is pain";
paradox.lastIndexOf("pain");     // Returns 30; indexOf( ) would return 0

The following returns 0 (the index of the first occurrence of the word "pain"), because we started the backward search before the second occurrence of "pain":

paradox.lastIndexOf("pain",29);  // Returns 0
4.6.5.5 No regular expressions

Note that regular expressions (a powerful tool used to recognize patterns in textual data) are not supported in ActionScript by default. However, developer Pavils Jurjans has made a custom RegExp object available at http://www.jurjans.lv/flash/RegExp.html.

4.6.6 Retrieving Portions of Strings

Sometimes a long string contains a sequence of characters that we'd like to access more conveniently. In the string "Steven Sid Mumby", for example, we may want to extract the last name, "Mumby". To extract a shorter string (or substring), we use one of these functions: substring( ), substr( ), splice( ), or split( ). We'll cover how each of them work before discussing performance considerations.

4.6.6.1 The substring( ) function

We use substring( ) to retrieve a sequence of characters from a string, based on starting and ending character indexes. The substring( ) function takes the following form:

string.substring(start_index, end_index)

where string is any literal string value or an identifier that contains a string, start_index is the index of the first character to include in the substring, and end_index is the character after the last character we want in our substring. If not provided, end_index defaults to string.length. Hence:

var fullName = "Steven Sid Mumby";
middleName = fullName.substring(7, 10);  // Assigns "Sid" to middleName
firstName = fullName.substring(0, 6);    // Assigns "Steven" to firstName
lastName = fullName.substring(11);       // Assigns "Mumby" to lastName

In reality, we wouldn't know where the first name, middle name, and last name begin and end, so we'd typically look for some delimiter, such as the space character to help us guess where the word breaks are (see the discussion of the split( ) function for an easier way to do this). Here we search for the last space in fullName and assume that the remainder of the string following it is the user's last name:

fullName = "Steven Sid Mumby";
lastSpace = fullName.lastIndexOf(" ");  // Returns 10
// Characters from lastSpace+1 to the string's end are presumably the last name
lastName = fullName.substring(lastSpace+1);
trace ("Hello Mr. " + lastName);

If start_index is greater than end_index, the two arguments are swapped automatically before the function executes. Although the following function invocations yield the same result, you shouldn't make a habit of using substring( ) with the indexes reversed because it makes your code harder to understand:

fullName.substring(4, 6);  // Returns "en"
fullName.substring(6, 4);  // Returns "en"
4.6.6.2 The substr( ) function

The substr( ) function extracts a sequence of characters from a string using a starting index and a length (in contrast to substring( ), which uses starting and ending indexes). The general form of substr( ) is:

string.substr(start_index, subLength)

where string is, as usual, any literal string value or an identifier that contains a string; start_index is the first character to include in the substring; and subLength specifies how many characters should be included in our string, starting at start_index and counting to the right. If subLength is omitted, the substring starts at start_index and ends with the last character in the original string. Here are some examples:

var fullName = "Steven Sid Mumby";
middleName = fullName.substr(7, 3);    // Assigns "Sid" to middleName
firstName = fullName.substr(0, 6);     // Assigns "Steven" to firstName
lastName = fullName.substr(11);        // Assigns "Mumby" to lastName

The start_index can be specified relative to the end of a string by using a negative number. The last character is -1, the second-to-last character is -2, and so on. So, the preceding three substr( ) examples could be written as:

middleName = fullName.substr(-9, 3);  // Assigns "Sid" to middleName
firstName = fullName.substr(-16, 6);  // Assigns "Steven" to firstName
lastName = fullName.substr(-5);       // Assigns "Mumby" to lastName

A negative subLength, however, is not allowed.

4.6.6.3 The slice( ) function

Like substring( ), the slice( ) function retrieves a sequence of characters from a string, based on starting and ending character indexes. While substring( ) can specify only the indexes relative to the beginning of the original string, slice( ) can specify them relative to the string's beginning or end.

The slice( ) function takes the following form:

string.slice(start_index, end_index)

where string is any literal string value or an identifier that contains a string and start_index is the first character to include in the substring. If start_index is a positive integer, it is a normal character index; if start_index is a negative integer, the equivalent character index is determined by counting backward from the end of the string (i.e., string.length + start_index). Finally, end_index is the character after the last character we want in our substring. If end_index is not provided, it defaults to string.length. If end_index is negative, the equivalent character index is determined by counting backward from the end of the string (i.e., string.length + end_index).

Using nonnegative indexes with slice( ) works just like substring( ). When using negative indexes, remember that you are not getting a substring with reversed characters (i.e., you are not getting a string from end_index to start_index, in that order). You are merely specifying the indexes relative to the end of the original string. Remember also that the last character of the string is -1, and the end_index argument specifies the character after the last character in your substring, so it's impossible to refer to the last character in the original string using a negative end_index. Take a careful look at how we use negative indexes to extract the following substrings:

var fullName = "Steven Sid Mumby";
middleName = fullName.slice(-9, -6);   // Assigns "Sid" to middleName.
firstName = fullName.slice(-16, -10);  // Assigns "Steven" to firstName.
lastName = fullName.slice(-5, -1);     // Assigns "Mumb" to lastName: not what
                                       // we want, but the best we can do with
                                       // a negative end_index.
lastName = fullName.slice(-5, 16)      // Assigns "Mumby" to lastName. Notice how 
                                       // we combine negative and positive indexes.
lastName = fullName.slice(-5)          // Also assigns "Mumby" to lastName.

The following code uses negative character indexes to check if the most recent letters entered into the text field guess_txt match one of the special words in the specialWords array. Note that the example uses the TextField object's onChanged( ) handler to detect user input and the String.toLowerCase( ) method to perform case-insensitive string comparison. For details, see TextField.onChanged( ) and String.toLowerCase( ) in the Language Reference.

var specialWords = ["MEGAN", "SING", "SUNDAY"];
   
guess_txt.onChanged = function ( ) {
  for (var i=0; i < specialWords.length; i++) {
    var guess = this.text.slice(-specialWords[i].length).toLowerCase( );
    var special = specialWords[i].toLowerCase( );
    if (guess =  = special) {
      trace("The user entered a special word!");
      break;
    }
  }
}
4.6.6.4 The split( ) function

So far, the string-extraction functions we've seen have retrieved only one character sequence at a time. If we want to rip out a bunch of substrings in one fell swoop, we can use the powerful split( ) function. (Because the split( ) function uses arrays, you may want to skip this function for now and come back after you've read Chapter 11.)

The split( ) function breaks a string into a series of substrings and returns those substrings in an array. The split( ) function takes the following form:

string.split(delimiter)

where string is any literal string value or an identifier that contains a string, and delimiter is the character or characters that indicate where string should be split. Commas, spaces, and tabs are typical delimiters. To break up a string at each comma, for example, we use:

theString.split(",")

One of the neat tricks we can pull with split( ) is to break a sentence up into individual words. In our coverage of the substring( ), substr( ), and slice( ) functions, we had to grab each name from the string "Steven Sid Mumby" manually. Look how much easier things are when we use split( ) with a space (" ") as the delimiter:

var fullName = "Steven Sid Mumby";
var names = fullName.split(" ");  // Man, that's easy!
// Now assign the names in our array to individual variables
firstName  = names[0];
middleName = names[1];
lastName   = names[2];
4.6.6.5 Flash 5 string extraction performance issues

Flash 5's substr( ) and slice( ) functions are actually implemented as veneer atop the old Flash 4 substring( ) function and, therefore, take marginally longer to execute. The speed difference is on the order of milliseconds but can be noticeable in intensive string processing. When carrying out highly repetitive operations in Flash 5, use Flash 4's substring( ) function for optimal performance, as follows:

fullName = "Steven Sid Mumby";
// Assign "Sid" to middleName using Flash 5 substr( ) function
middleName = fullName.substr(7, 3);  
// Assign "Sid" to middleName using Flash 4 substring( ) function.
// Note that character indexes start at 1 with Flash 4's substring( ).
middleName = substring(fullname, 8, 3);

For the benefit of Flash 5 developers, Branden Hall has rewritten the methods of the String class to improve their speed. See:

http://chattyfig.figleaf.com/~bhall/code/string.as

In Flash Player 6, string performance was greatly improved, so this workaround is not necessary.

4.6.7 Combining String Examination with Substring Extraction

We've seen how to search for characters in a string and how to extract characters from a string. These two operations are most powerful when we put them together.

Most of the examples we've seen so far use literal expressions as arguments, like this:

var msg = "Welcome to my website!";
var firstWord = msg.substring(0, 7);  // 0 and 7 are numeric literals

That's a decent demonstration of the way substring( ) works, but it doesn't represent the typical real-world use of substring( ). More often, we don't know the content of the string in advance and we must generate our arguments dynamically. For example, instead of saying something static like, "Get me the substring from index 0 to index 7," we usually say something dynamic like, "Get me the substring starting from the first character and ending at the first occurrence of a space in this string." This more flexible approach doesn't require us to know the content of a string in advance. Here we extract the first word of the variable msg, by combining substring( ) with indexOf( ):

var firstWord = msg.substring(0, msg.indexOf(" "));

The expression msg.indexOf(" ") evaluates to the numeric index of the first space in msg. Our technique will work regardless of the space's location. This allows us to work with strings that change while our program is running and saves us from counting characters, which is prone to error.

The combinations of string examination and string extraction are practically endless. Example 4-3 extracts the second word of the msg variable without hard-coding the character indexes. In natural language, we want to "extract a substring from msg, starting with the character after the first occurrence of a space and ending with the character before the second occurrence of a space." We store the location of the first and second spaces as variables, making the code easier to follow.

Example 4-3. Retrieving the second word of a string
var msg = "Welcome to my website!";
firstSpace = msg.indexOf(" ");                   // Find the first space
secondSpace = msg.indexOf(" ", firstSpace + 1);  // Find the next space
// Now extract the second word
var secondWord = msg.substring(firstSpace + 1, secondSpace);

4.6.8 Character Case Conversion

We can convert a string to upper- or lowercase using the built-in toUpperCase( ) and toLowerCase( ) functions. These functions are typically used to display a string with nice formatting or to compare strings with different cases.

4.6.8.1 The toUpperCase( ) function

The toUpperCase( ) function converts all of the characters in a string to uppercase (i.e., capital letters) and returns the converted version. If no uppercase version of a given character exists, the character is returned unchanged. The general form of toUpperCase( ) is:

string.toUpperCase()

where string is any literal string value or an identifier that contains a string. Here are some examples:

"listen to me".toUpperCase();       // Yields the string "LISTEN TO ME"
var msg1 = "Your Final Score: 234";
var msg2 = msg1.toUpperCase();      // Set msg2 to "YOUR FINAL SCORE: 234"

Note that toUpperCase( ) does not affect the string on which it's called; it merely returns an uppercase copy of that string. The following example shows the difference:

var msg = "Forgive me, I forgot to bring my spectacles.";
msg.toUpperCase();
trace(msg);    // Displays: "Forgive me, I forgot to bring my spectacles."
               // msg was unaffected by the toUpperCase( ) invocation.
4.6.8.2 The toLowerCase( ) function

The toLowerCase( ) function changes the characters in a string from upper- to lowercase. For example:

// Set normal to "this sentence has mixed caps!"
normal = "ThiS SenTencE Has MixED CaPs!".toLowerCase();

To compare two strings in a case-insensitive manner, first convert them both to the same case, such as:

if (userEntry.toLowerCase( ) =  = password.toLowerCase()) {
  // They get secret access
}

We can use toUpperCase( ) and toLowerCase( ) together to capitalize the first letter of a word, as follows:

var word = "fLASH";
var firstLetter = word.charAt(0).toUpperCase( );
var remainderOfWord = word.substring(1).toLowerCase( );
initialCapWord = firstLetter + remainderOfWord;
trace(initialCapWord);  // Displays: Flash

Example 4-4 shows how we can have a little fun using the case-conversion and string functions to animate text in a text field. It adds a new method, caseAni( ), to all text fields. Attach the script to frame 1 of a new movie and see what happens. Note that the code uses several advanced techniques that we haven't encountered yet. Come back and study it again once you've read Chapter 9 and Chapter 12.

Example 4-4. Character case animation
// Add a new caseAni( ) method to the built-in TextField class.
TextField.prototype.caseAni = function (msg) {
  // Store a reference to the current text field in tf. We'll need to
  // access it from the nested function moveUppercaseLetter( ).
  var tf = this;
  tf.upperIndex = 0;  // The current location of the uppercase letter.
  tf.msg = msg;       // The message to animate.
   
  // Start the animation running by calling 
  // the moveUppercaseLetter( ) function every 100 milliseconds.
  var id = setInterval(moveUppercaseLetter, 100);
   
  // Define the nested moveUppercaseLetter( ) function. Here's where we do
  // all our string manipulation.
  function moveUppercaseLetter ( ) {
    // Chop the msg string into three pieces and make the middle one uppercase.
    var part1 = tf.msg.slice(0, tf.upperIndex);
    var part2 = tf.msg.charAt(tf.upperIndex);
    var part2 = part2.toUpperCase( );
    var part3 = tf.msg.slice(tf.upperIndex+1, tf.msg.length);
    tf.msg  = part1 + part2 + part3;
   
    // Display the formatted msg string.
    tf.text = tf.msg;
   
    // Reset the string for next time.
    tf.msg  = tf.msg.toLowerCase( );
   
    // Move the uppercase letter over one to the right.
    tf.upperIndex++;
   
    // If the uppercase letter is at the end of the string, move 
    // it back to the beginning.
    if (tf.upperIndex > (tf.msg.length - 1)) {
      tf.upperIndex = 0;
    }
  }
}
   
// Try it out on a text field instance!
this.createTextField("msgOutput_txt", 1, 0, 0, 300, 30);
// Use a monospaced font...
msgOutput_txt.setNewTextFormat(new TextFormat("_typewriter", 16));
msgOutput_txt.caseAni("my what fat cheeks you have");

4.6.9 Character Code Functions

In Section 4.5.2.3, we saw how to insert characters into a string using escape sequences. ActionScript also includes two built-in functions for working with character code points in strings: fromCharCode( ) and charCodeAt( ).

4.6.9.1 The fromCharCode( ) function

We can create any character or series of characters by invoking the fromCharCode( ) function. Unlike the other string functions, fromCharCode( ) is not called on a string literal or an identifier that contains a string; it is called as a method of the built-in String class, like this:

String.fromCharCode(code_ point1, code_ point2, ...)

Every fromCharCode( ) call starts with String.fromCharCode. Then one or more code points (representing the characters we want to create) are supplied as arguments. Unlike Unicode escape sequences, which must be in hex, the code points in a fromCharCode( ) call can be expressed in either decimal or hex. If you're unfamiliar with hex numbers you may, therefore, find fromCharCode( ) easier to use than Unicode escape sequences. For values less than 128, fromCharCode( ) essentially converts a numeric code to its equivalent ASCII character. Here are some examples:

// Set lastName to "moock"
lastName = String.fromCharCode(109, 111, 111, 99, 107);
// For comparison, let's do the same thing with Unicode escape sequences
lastName = "\u006D\u006F\u006F\u0063\u006B";
// Make a copyright symbol
copyNotice = String.fromCharCode(169) + " 2003";
// Make a euro sign
price = "5.99 " + String.fromCharCode(0x20AC);

You may encounter the deprecated Flash 4 character-creation functions, chr( ) and mbchr( ), when examining legacy code. The fromCharCode( ) function should be used in Flash 5 and later.

4.6.9.2 The charCodeAt( ) function

To determine the code point of any character in a string, we use the charCodeAt( ) function, which takes the following form:

string.charCodeAt(index)

where string is any literal string value or an identifier that contains a string, and index is the position of the character we're examining. The charCodeAt( ) function returns a decimal integer that matches the Unicode code point of the character at index. For values less than 128, charCodeAt( ) essentially converts a character to its equivalent ASCII code. For example:

var msg = "A is the first letter of the Latin alphabet.";
trace(msg.charCodeAt(0));  // Displays: 65 (the code point for "A")
trace(msg.charCodeAt(1));  // Displays: 32 (the code point for a space)

We normally use charCodeAt( ) to perform string handling with characters we can't type directly using a keyboard. For example, in the following code we check whether a character is the copyright symbol:

msg = String.fromCharCode(169) + " 2003";
if (msg.charCodeAt(0) =  = 169) {
  trace("The first character of msg is a copyright symbol.");
}

You may encounter the deprecated Flash 4 code point functions, ord( ) and mbord( ), when examining legacy code. The charCodeAt( ) function should be used in Flash 5 and later.

4.6.10 Executing Code in a String with eval

In ActionScript, the eval( ) function converts a string to an identifier (i.e., a variable name). But to thoroughly understand the ActionScript eval( ) function, you must first understand how JavaScript's analogous eval( ) function works. In JavaScript, eval( ) is a built-in function that converts any string to a block of code and then executes that block of code. The syntax for JavaScript's eval( ) is:

eval(string)

When eval( ) is executed in JavaScript, the interpreter converts string to executable code, runs that code, and returns the resulting value (if a value is generated). Consider the following JavaScript examples:

eval("parseInt('1.5')");  // Calls the parseInt( ) function, which returns 1
eval("var x = 5");        // Creates a new variable named x and sets its value to 5

If you've never seen eval( ) before, you may be thinking, "When would I ever have a string with code in it? Why not just write the code out?" Answer: because eval( ) lets you dynamically generate code when you need to. For example, eval( ) could be used to programmatically create functions to be assigned as event handler callbacks for a series of similar objects.

ActionScript's eval( ) function supports a small subset of its JavaScript cousin's functionality: it works only when its argument is an identifier. Hence, ActionScript's eval( ) function can only retrieve the data associated with the specified identifier. For example:

var num = 1;
var person1 = "Eugene";
trace (eval("person" + num));  // Displays: "Eugene"

Even in this pared-back form, eval( ) is quite useful. Here we generate a series of movie clips dynamically with a loop. We place our clips in an array by using eval( ) to refer to them:

for (var i = 0; i < 10; i++) {
  duplicateMovieClip("ballParent", "ball" + i, i);
  balls[i] = eval("ball" + i);
}

Note, however, that in nearly all cases eval( ) can be replaced by the array-access operator to generate dynamic clip references. For example:

duplicateMovieClip("ballParent", "ball" + i , i);
balls[ballCount] = _root ["ball" + i];

The eval( ) function was used frequently in Flash 4 to generate variables dynamically because support for arrays wasn't available until Flash 5. Such uses of eval( ) should be rewritten using arrays when upgrading legacy code.


Table of Contents