You ask the user to enter her city. Then you check her city against a
list of the 5 cleanest
cities.
If the user enters "Cheyenne" or any of the other cleanest cities, your
code displays an
alert telling her that it's one of the cleanest cities.
But what if she enters "cheyenne" instead of "Cheyenne"—as some users
inevitably will?
When that happens, there will be no match. JavaScript is literal-minded.
A human knows that in this context "cheyenne" means "Cheyenne." But
JavaScript doesn't.
We need some way to get JavaScript to recognize the uncapitalized
version as a match.
One way would be to expand the cleanestCities array to include the
uncapitalized
versions of all the city names:
var cleanestCities = ["Cheyenne", "cheyenne", "Santa Fe", "santa fe",
"Tucson", tucson", "Gr eat Falls",
"great falls", "Honolulu", "honolulu"];
This works up to a point, but it's a lot of extra coding. Plus, if the
user enters "santa Fe ,"
"Santa fe," or "sAnta Fe," we're back to the original problem. To cover
all these possibilit es
and others, it would take a mile of code.
The solution is to code the array elements in lower-case, and convert
the user's input,
whatever it is, to lower-case, so we always have apples to compare with
apples.
1 var cityToCheck = prompt("Enter your city");
2 cityToCheck = cityToCheck.toLowerCase();
3 var cleanestCities = ["cheyenne", "santa fe", "tucson", "great falls",
"honolulu"];
4 for (var i = 0; i <= 4; i++) {
5 if (cityToCheck === cleanestCities[i]) {
6 alert("It's one of the cleanest cities");
7 }
8 }
Line 2 is what's new here:
2 cityToCheck = cityToCheck.toLowerCase();
The converted string is assigned to a variable. In this case, it's the
same variable whose
string is being converted, cityToCheck. Note that the keyword
toLowerCase must be in
camelCase.
Note too that the toLowerCase method converts all the characters of the
string to lowercase, not just the initial letters. For example,
"ChEyEnNe" becomes "cheyenne."
You could go the other way and convert everything to upper-case, then
test against
"CHEYENNE," "SANTA FE, " etc. Most coders prefer the lower-case method.
To convert the
string to upper-case, you'd write:
2 cityToCheck = cityToCheck.toUpperCase();
You've asked the user to give you the name of a city. You want to
convert the name she's
given you to a name with an initial cap. Whether she's input "boston,"
"BOSTON", or
"bosTon," you want to normalize the input to "Boston." The toLowerCase
and toUpperCase
methods you learned in the last chapter won't get the job done on their
own, because they make
the same wholesale change to every character in the string. But if you
break the string up into
two segments, you can use these methods to get the string into the shape
you want. (For now,
I'll ignore the possibility that the city name might be made up of two
or more words, like New
Orleans or Sault Ste. Marie.)
To copy a section of a string, you use the slice method. Suppose the
user has entered a
string, and the string has been assigned to the variable cityToCheck.
The following code
copies the first character of the string and assigns it to the variable
firstChar. The original
value of cityToCheck doesn't change. If cityToCheck is "Boston",
firstChar is "B".
var firstChar = cityToCheck.slice(0, 1);
Things to be aware of:
A string is indexed like an array. Only, instead of each index number
referring to an
element, it refers to a character.
Like array indexing, string indexing begins with 0.
In the slice method, the first number inside the parentheses is the
index of the first
character in the slice. The second number is not, however, the last
character in the slice.
It's the first character after the slice. If you subtract the first
index from the second index,
you'll always get the length of the slice.
Here's another example.
var someChars = cityToCheck.slice(2, 5);
Again let's say that the string is "Boston". The slice begins with the
index-2 (the third)
character, "s". It ends with the character before the index-5 character,
"n". someChars is "sto".
If you omit the second number inside the parentheses, JavaScript
includes all the
characters to the end of the string.
var someChars = cityToCheck.slice(2);
The slice begins with the index-2 (the third) character, "s". Since no
cutoff at the end is
specified, the slice ends with the last character of the string.
someChars is "ston".
Now we have a way to capitalize the first character of a string and
insure that the
remaining letters are lower-case.
1 var firstChar = cityToCheck.slice(0, 1);
2 var otherChars = cityToCheck.slice(1);
3 firstChar = firstChar.toUpperCase();
4 otherChars = otherChars.toLowerCase();
5 var cappedCity = firstChar + otherChars;
Here's what happens in the code above, line-by-line:
1. Copies the first character of the string and assigns it to the
variable firstChar.
2. Copies all the characters from the second one to the end and assigns
them to the variable
otherChars.
3. Caps the first character.
4. Lower-cases the other characters.
5. Concatenates both parts to re-form the whole string.
Sometimes it's useful to know how many characters are in a string. For
example, suppose
you want to slice the first three characters from any string than
exceeds three characters in
length, for example, slicing "Nov" from "November". To find the number
of characters in a
string, you use the same language you've already learned to find the
number of elements in an
array.
1 var month = prompt("Enter a month");
2 var charsInMonth = month.length;
3 if (charsInMonth > 3) {
4 monthAbbrev = month.slice(0, 3);
5 }
Line 2 counts the characters in the string and assigns the number to the
variable
charsInMonth.
Being able to measure the number of characters in a string can come in
handy. For
example, suppose you want to loop through a string, checking to see if
it has any double spaces
in it. You can use the character count as the loop limiter. Here's some
code that checks for
double spaces in a string and displays an alert if they're found.
1 var str = prompt("Enter some text");
2 var numChars = str.length;
3 for (var i = 0; i < numChars; i++) {
4 if (str.slice(i, i + 2) === " ") {
5 alert("No double spaces!");
6 break;
7 }
8 }
Line 2 counts the number of characters in the string and assigns the
number to the variable
numChars. In line 3, this number is used as the loop limiter. The loop
continues to run only as
long as the counter, i, is less than the number of characters in the
string. (Remember, the length
is 1-based, and the counter is 0-based, so the loop has to stop 1 short
of the length number.)
Line 4 moves through the string character-by-character, examining each
2-character segment,
looking for double spaces.
The New Yorker magazine doesn't allow the phrase "World War II. " They
say it should
be "the Second World War." So let's search the following sentence for
the banned characters
and replace them with the phrase that the New Yorker prefers.
It is startling to think that, even in the darkest depths of World War
II, J. R. R. Tolkien was
writing the trilogy, which contains, with the weird applicability
available only to poetry and
myth, the essential notion that the good gray wizard can understand the
evil magi precisely
because he is just enough like them to grasp their minds and motives in
ways that they cannot
grasp his.
You already know a way to find the banned segment and replace it.
Suppose the
paragraph above has been assigned to the variable text.
1 for (var i = 0; i < text.length; i++) {
2 if (text.slice(i, i + 12) === "World War II") {
3 text = text.slice(0, i) + "the Second World War" + text.slice(i + 12);
4 }
5 }
The code loops through the string looking for "World War II." Line 2
progresses through
the string character-by-character, examining each 12-character sequence.
If it finds "World
War II," line 3 concatenates three segments: all the characters
preceding "World War II," the
substitute phrase "the Second World War," and then all the characters
following "World War
II."
But JavaScript has a more efficient way to accomplish this, using the
indexOf method.
var firstChar = text.indexOf("World War II");
If the segment exists, the method finds the index of the first character
of the segment and
assigns it to the variable firstChar. If the segment doesn't exist, the
method assigns -1 to the
variable, so you know it's not there.
Now we can replace the banned phrase with the preferred phrase with less
coding.
1 var firstChar = text.indexOf("World War II");
2 if (firstChar !== -1) {
3 text = text.slice(0, firstChar) + "the Second World War" +
text.slice(firstChar + 12);
4 {
Line 1 checks for the phrase, assigning the index of the first character
of the phrase to the
variable firstChar—if the phrase is found. If it isn't found, -1 is
assigned to the variable. If
the variable doesn't have the value -1 (line 2)—if the phrase has been
found—the
concatenation in line 3 replaces the offending phrase with the correct
pharse.
The indexOf method finds only the first instance of the segment you're
looking for. In the
example above, you could overcome this limitation by looping. You'd
change the first instanc
of "World War II" to "the Second World War," then in the next loop
iteration, find the next
surviving instance and change that, and so on.
To find the last instance of a segment in a string, use lastIndexOf. The
following code
finds the index of the first character of the last instance of the
segment, the second "be". The
variable segIndex winds up with a value of 16, the index of "b" in the
second "be".
1 var text = "To be or not to be.";
2 var segIndex = text.lastIndexOf("be");
The user has entered his first name. The string has been assigned to the
variable
firstName. You want to extract the first character. You already know one
way to do it.
var firstChar = firstName.slice(0, 1);
Here's an alternate way to do it that's more direct.
var firstChar = firstName.charAt(0)
The code above finds a single character at index-0 (the beginning) of
the string
represented by the variable firstName and assigns it to the variable
firstChar.
The following code finds the last character in the string.
var lastChar = name.charAt(name.length - 1);
The following code cycles through a string looking for an exclamation
point. If the
character is found, an alert displays.
1 for (var i = 0; i < text.length; i++) {
2 if (text.charAt(i) === "!") {
3 alert("Exclamation point found!");
4 break;
5 }
6 }
Note: The indexOf method can only identify the character at a particular
location. It can't
change the character at a location.
In previous chapters you learned two different ways to replace "World
War II" with "the
Second World War" in a string. First, there was the loop-and-slice
approach.
1 for (var i = 0; i < text.length; i++) {
2 if (text.slice(i, i + 12) === "World War II") {
3 text = text.slice(0, 1) + "the Second World War" + text.slice(i + 12);
4 }
5 }
You improved on that rather crude approach when you learned the indexOf
method.
1 var firstChar = text.indexOf("World War II");
2 if (firstChar !== -1) {
3 text = text.slice(0, firstChar) + "the Second World War" +
text.slice(firstChar + 12)
; 4 }
But JavaScript provides a more straightforward way still, the replace
method.
var newText = text.replace("World War II", "the Second World War");
The first string inside the parentheses is the segment to be replaced.
The second string is
the segment to be inserted. In the above code, the segment "World War
II" is replaced by the
segment "the Second World War" in the string represented by the variable
text, and the
revised string is assigned to the new variable newText.
If you assign the revised string to a new variable, as in the example
above, the original
string is preserved. If you want the original string to be replaced by
the revised string, assign
the revised string to the original variable.
text = text.replace("World War II", "the Second World War");
In the examples above, only the first instance of a string is replaced.
If you want to
replace all instances, you must let JavaScript know that you want a
global replace.
var newText = text.replace(/World War II/g, "the Second World War");
In a global replace, you enclose the segment to be replaced by slashes
instead of
quotation marks, and follow the closing slash with "g" for "global." The
segment to be inserted
is enclosed by quotation marks, as in a one-time replace.