Wednesday, December 28, 2011

Java's character and assorted string classes support text-processing - 28


For a practical demonstration of StringTokenizer's methods, I created a PigLatin application that translates English text to its pig Latin equivalent. For those unfamiliar with the pig Latin game, this coded language moves a word's first letter to its end and then adds ay. For example: computer becomes omputercay; Java becomes Avajay, etc. Punctuation is not affected. Listing 6 presents PigLatin's source code:
Listing 6: PigLatin.java
// PigLatin.java
import java.util.StringTokenizer;
class PigLatin
{
   public static void main (String [] args)
   {
      if (args.length != 1)
      {
          System.err.println ("usage: java PigLatin phrase");
          return;
      }
      StringTokenizer st = new StringTokenizer (args [0], " \t:;,.-?!");
      while (st.hasMoreTokens ())
      {
         StringBuffer sb = new StringBuffer (st.nextToken ());
         sb.append (sb.charAt (0));
         sb.append ("ay");
         sb.deleteCharAt (0);
         System.out.print (sb.toString () + " ");
      }
      System.out.print ("\r\n");
   }
}

To see what Hello, world! looks like in pig Latin, execute java PigLatin "Hello, world!". You see the following output:
elloHay orldWay

According to pig Latin's rules, the output is not quite correct. First, the wrong letters are capitalized. Second, the punctuation is missing. The correct output is:
Ellohay, Orldway!

Use what you've learned in this article to fix those problems.
Review
Java's Character, String, StringBuffer, and StringTokenizer classes support text-processing programs. Such programs use Character to indirectly store char variables in data structure objects and access a variety of character-oriented utility methods; use String to represent and manipulate immutable strings; use StringBuffer to represent and manipulate mutable strings; and use StringTokenizer to extract a string's tokens.
This article also cleared up three mysteries about strings. First, you saw how the compiler and classloader allow you to treat string literals (at the source-code level) as if they were String objects. Thus, you can legally specify synchronized ("sync object") in a multithreaded program requiring synchronization. Second, you learned why Strings are immutable, and how immutability works with internment to save heap memory when a program requires many strings and to allow fast string searches. Finally, you learned what happens when you use the string concatenation operator to concatenate strings and how StringBuffer is involved in that task.

Using Applet dimension to print center aligned text

package org.best.example;
   
    /*
            Using Applet dimension to print center aligned text Example
            This Java example shows how to print text in center of an applet window using
            Dimension class.
    */
    
    import java.applet.Applet;
    import java.awt.Dimension;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    
    /*
            <applet code = "AppletDimensionExample" width = 500 height = 300>
            </applet>
    */
    
    public class AppletDimensionExample extends Applet{
          
            public void paint(Graphics g){
                    int x,y;
                    String s = "Hello World";
                  
                    //get applet size using getSize method
                    Dimension d = getSize();
                    Font f = new Font("Arial",Font.BOLD,24);
                    g.setFont(f);
                  
                    //determine x and y coordinates
                    FontMetrics fm = g.getFontMetrics();
                    x = d.width/2 - fm.stringWidth(s)/2;
                    y = d.height/2 - fm.getHeight();
                  
                    //print string at specified location using drawString method
                    g.drawString(s,x,y);
            }
    }

Tuesday, December 27, 2011

Java's character and assorted string classes support text-processing - 27


Earlier, I cautioned you against relying on countTokens() for determining the number of tokens to extract. countTokens()'s return value is often meaningless when a program dynamically changes a StringTokenizer's delimiters with a nextToken(String delim) method call, as the following fragment demonstrates:
String record = "Ricard Santos,Box 99,'Sacramento,CA'";
StringTokenizer st = new StringTokenizer (record, ",");
int ntok = st.countTokens ();
System.out.println ("Number of tokens = " + ntok);
for (int i = 0; i < ntok; i++)
{
     String token = st.nextToken ();
     System.out.println (token);
     if (token.startsWith ("Box"))
         st.nextToken ("'"); // Throw away comma between Box 99 and
                             // 'Sacramento,CA'
}

The code creates a String that simulates a database record. Within that record, commas delimit fields (record portions). Although there are four commas, only three fields exist: a name, a box number, and a city-state. A pair of single quotes surround the city-state field to indicate that the comma between Sacramento and CA is part of the field.
After creating a StringTokenizer recognizing only comma characters as delimiters, the current thread counts the number of tokens, which subsequently print. The thread then uses that count to control the duration of the loop that extracts and prints tokens. When the Box 99 token returns, the thread executes st.nextToken ("'"); to change the delimiter from a comma to a single quote and discard the comma token between Box 99 and 'Sacramento,CA'. The comma token returns because st.nextToken ("'"); first replaces the comma with a single quote before extracting the next token. The code produces this output:
Number of tokens = 4
Ricard Santos
Box 99
Sacramento,CA
Exception in thread "main" java.util.NoSuchElementException
        at java.util.StringTokenizer.nextToken(StringTokenizer.java:232)
        at STDemo.main(STDemo.java:18)

The output indicates four tokens because three commas imply four tokens. But after displaying three tokens, a NoSuchElementException object is thrown from st.nextToken ();. The exception occurs because the program assumes that countTokens()'s return value indicates the exact number of tokens to extract. However, countTokens() can only base its count on the current set of delimiters. Because the fragment changes those delimiters during the loop, via st.nextToken ("'");, method countTokens()'s return value is no longer valid.
Caution
Do not use countTokens()'s return value to control a string tokenization loop's duration if the loop changes the set of delimiters via a nextToken(String delim) method call. Failure to heed that advice often leads to one of the nextToken() methods throwing a NoSuchElementException object and the program terminating prematurely.

Set Status Message in Applet Window

package org.best.example;
   
    /*
            Set Status Message in Applet Window Example
            This java example shows how to set a status message of an applet window
            using showStatus method of an Applet class.
    */
    
    /*
    <applet code="SetStatusMessageExample" width=200 height=200>
    </applet>
    */
    
    
    import java.applet.Applet;
    import java.awt.Graphics;
    
    public class SetStatusMessageExample extends Applet{
    
            public void paint(Graphics g){
                    /*
                     * Show status message in an Applet window using
                     * void showStatus(String msg) method of an applet class.
                     */
                  
                    //this will be displayed inside an applet
                    g.drawString("Show Status Example", 50, 50);
                  
                    //this will be displayed in a status bar of an applet window
                    showStatus("This is a status message of an applet window");
            }
    }

Monday, December 26, 2011

Java's character and assorted string classes support text-processing - 26


Token extraction
StringTokenizer provides four methods for extracting tokens: public int countTokens(), public boolean hasMoreTokens(), public String nextToken(), and public String nextToken(String delim). The countTokens() method returns an integer containing a count of a string's tokens. Use this return value to determine the maximum tokens to extract. However, you should call hasMoreTokens() to determine when to end tokenizing because countTokens() is undependable (as you will see). hasMoreTokens() returns a Boolean true value if at least one more token exists to extract. Otherwise, that method returns false. Finally, the nextToken() and nextToken(String delim) methods return a String's next token. But if no more tokens are available, either method throws a NoSuchElementException object. nextToken() and nextToken(String delim) differ only in that nextToken(String delim) lets you reset a StringTokenizer's delimiter characters to those characters in the delim-referenced String. Given this information, the following code, which builds on the previous fragment, shows how to use the previous three StringTokenizers to extract a string's tokens:
System.out.println ("count1 = " + stok1.countTokens ());
while (stok1.hasMoreTokens ())
   System.out.println ("token = " + stok1.nextToken ());
System.out.println ("\r\ncount2 = " + stok2.countTokens ());
while (stok2.hasMoreTokens ())
   System.out.println ("token = " + stok2.nextToken ());
System.out.println ("\r\ncount3 = " + stok3.countTokens ());
while (stok3.hasMoreTokens ())
   System.out.println ("token = " + stok3.nextToken ());

The fragment above divides into three parts. The first part focuses on stok1. After retrieving and printing a token count, a while loop calls nextToken() to extract all tokens if hasMoreTokens() returns true. The second and third parts use identical logic for the other StringTokenizers. If you execute the code fragment, you observe the following output:
count1 = 6
token = A
token = sentence
token = to
token = tokenize.|A
token = second
token = sentence.
count2 = 2
token = A sentence to tokenize.
token = A second sentence.
count3 = 13
token = A
token = 
token = sentence
token = 
token = to
token = 
token = tokenize.
token = |
token = A
token = 
token = second
token = 
token = sentence.

The output above reveals three different token counts for the same string. The counts differ because the sets of delimiters differ. For stok1, the default delimiter set applies. For stok2, only one delimiter is present: the vertical bar. stok3 records a space and a vertical bar as its delimiters. The output's final portion reveals that the space and vertical bar delimiters return as tokens due to passing true as returnDelim's value in the stok3 call.