Skip to main content

Section 7.8 Processing Each Character in a String

Many string-processing applications require you to process each character in a string. For example, to encrypt the string “hello” into “jgnnq”, we have to go through each letter of the string and change each character to its substitute.

Subsection 7.8.1 Counting Loops

These types of algorithms usually involve a counting loop bounded by the length of the string. Recall that the length() method determines the number of characters in a String and that strings are zero indexed. This means that the first character is at index 0, and the last character is at index length()-1. For example, to print each character in a string on a separate line, we would step through the string from its first to its last character and print each character::

// Precondition:  str is not null
// Postcondition: the letters in str will have been printed
public void printLetters(String str)
  for (int k = 0; k < str.length(); k++)// For each char
    System.out.println(str.charAt(k));  //  Print it

Note that our loop bound is k < str.length(), since the index of the last character of any String is length()-1. Note also the use of str.charAt(k) to retrieve the kth character in str on each iteration of the loop.

Note the use of pre- and postconditions in the method's comment block. The precondition states that str has been properly initialized — that is, it is not null. The postcondition merely states the expected behavior of the method.

Subsection 7.8.2 Off-by-One Error

A frequent error in coding counter-controlled loops is known as the off-by-one error, which can occur in many different ways. For example, if we had coded the loop boundary condition as k <= str.length(), this would cause an off-by-one error, because the last character in str is at location length()-1. This would lead to a Java IndexOutOfBoundsException, which would be reported as soon as the program executed this statement.

The only way to avoid off-by-one errors is to check your loop bounds whenever you code a loop. Always make sure you have the loop counter's initial and final values correct.

Subsection 7.8.3 Example: Counting Characters

As another example of an algorithm that processes each character in a string, consider the problem of computing the frequency of the letters in a given document. Certain text analysis programs, such as programs that analyze encrypted data and spam filters, perform this type of function.

The countChar() method will count the number of occurrences of any particular character in a String (Listing 7.8.2). This method takes two parameters: a String parameter that stores the string being searched and a char parameter that stores the character being counted.

// Precondition: Neither str nor ch are null
// Postcondition: countchar() == the number of ch in str
public int countChar(String str, char ch)
  int counter = 0;              // Initialize a counter
  for (int k = 0; k < str.length(); k++)// For each char
    if (str.charAt(k) == ch)           //  If it's a ch
      counter++;                          //   count it
  return counter;                  // Return the result
Listing 7.8.2. A method to count the occurrence of a particular character in a string.

Begin by initializing the local variable, counter, to 0. As in the previous example, the for loop here will iterate through each character of the String—from 0 to length()-1. On each iteration a check is made to see if the character in the kth position (str.charAt(k)) is the character being counted. If so, counter is incremented. The method ends by returning counter, which, when the method completes, will store an integer representing the number of ch's in str.

Subsection 7.8.4 Example: Reversing a String

Another interesting method that processes each character in a string is the reverse() method. This is a method that reverses the letters in a string. For example, the reverse of "java" is "avaj".

The algorithm for the reverse() method should use a simple counting loop to reverse the letters in its String parameter. In this case, however, we can process the string from right to left, beginning at its last character and ending with its first character. That way we can just append each character, left to right, in the result string:

  * Pre:  s is any non null string
  * Post: s is returned in reverse order
public String reverse(String s)
    StringBuffer result = new StringBuffer();
    for (int k = s.length()-1; k >= 0; k--) {
    } //for
    return result.toString();
} // reverse()

Note that as in the other string-manipulation algorithms — for example, keywordSearch() — we should us a StringBuffer to store the method's result. Thus we declare the resultStringBuffer at the beginning of the method and convert it back into a String at the end of the method.

Subsection 7.8.5 Example: Capitalizing the First Letter

Another string manipulation method is the capitalize() method, which returns a String whose initial letter is capitalized but whose other letters are lowercase — for example, “Hello”. We use the statictoUpperCase() and toLowerCase() methods from the Character class to convert individual letters. The algorithm converts the first letter to upper case and then loops through the remaining letters converting each to lowercase:

 * Pre:  s is any non null string
 * Post: s is returned with only its first letter capitalized
public String capitalize(String s)
  if (s.length() == 0)    // Special case: empty string
    return s;
  StringBuffer result = new StringBuffer();
                          // Convert the first letter
  for (int k = 1; k < s.length(); k++) { // And the rest
  } //for
  return result.toString();
} // capitalize()

Exercises Self-Study Exercises

1. String processor.

Run this program to see how it works and then modify it to perform the following tasks.

  1. Add reverse() as a static method and write code to test it in the main while loop.

  2. Define and test a new method, removeBlanks(), that accepts a string parameter and returns a string with all blank characters removed.

Subsection 7.8.6 Miscellaneous String Methods

In addition to the several String class methods we have discussed — valueOf(), equals(), indexOf(), lastIndexOf(), charAt(), substring()Table 7.8.4 shows some of the other useful methods in the String class.

Table 7.8.4. Some useful String methods applied to the literal string “Perfection”.
Method Signature Example
boolean endsWith(String suffix) "Perfection".endsWith("tion")\(\Rightarrow\) true
boolean startsWith(String prefix) "Perfection".startsWith("Per")\(\Rightarrow\) true
boolean startsWith(String prefix, int offset) "Perfection".startsWith("fect",3)\(\Rightarrow\) true
String toUpperCase() "Perfection".toUpperCase()\(\Rightarrow\) "PERFECTION"
String toLowerCase() "Perfection".toLowerCase()\(\Rightarrow\) "perfection"
String trim() "Perfection".trim()\(\Rightarrow\) "Perfection"

Note that because of what we said about the read-only nature of String, methods such as toUpperCase(), toLowerCase(), and trim() do not change their string. Instead they produce a new string. If you want to use one of these methods to convert a string, you must reassign its result back to the original string:

String s = new String("hello world");
s = s.toUpperCase(); // s now equals "HELLO WORLD"

You have attempted of activities on this page.