Saturday, November 12, 2011

Program to Create Acronyms

This came from the book as an example, but I wanted to make it better :)

This program, taken from the unit in the book that deals with characters and string manipulation, lets the user input a string (usually a sentence of multiple words) and get an acronym back. The method that builds the acronym works by taking the very first character, and after that, hunting for space characters. It looks at the character right *after* each space and slices that following character to add to the acronym.

There is a bug however-- what happens if the user enters in "hello**world" (say that "*" is a space here)? The acronym SHOULD be "hw", but instead you get "h*w." No good.

I wrote a program, first to test out the buggy method to verify what the acronym for "hello**world" would be, and then to fix that edge case.

What it looks like:



/* File: acronymBuilder
* --------------------
* This program takes a string and returns the acronym, or, a string made up of the first character of each
* word. It works via a private method that takes the first character and saves it to the instance variable
* "result." Then it finds each space, takes the character directly after the space, and takes that following 
* character and appends it to "result" until there are no spaces left.
* 
* This method originally appeared in ch 10 of Roberts' "The Art and Science of Java," but the original method
* didn't account for inputs where there were 2 spaces in a row, so I'm making the modification and writing a
* run method to use it.
 */
import acm.program.*;
 
public class acronymBuilder extends ConsoleProgram {
    public void run(){
        String initialString = readLine("Enter a string you want to generate the acronym for:");
        String result = acronym(initialString);
        println(result);
    }
    
    private String acronym(String str) {
        String result = str.substring(0, 1); 
        int pos = str.indexOf(' '); 
        while (pos != -1) {
            if (str.charAt(pos + 1) != ' ') { 
                result += str.substring(pos + 1, pos + 2); 
            }
            pos = str.indexOf(' ', pos + 1); //Finds the next space sign           
        } 
    return result;
    }
}
What made it tough: There were a couple bugs that stumped me along the way.
First, I wanted to write an "if" statement checking to see if there are two space signs in a row. Specifically, you look at a space sign and see if the character after it is also a space sign. The "if" statement looked like this:

if (str.charAt(pos + 1) != " ");

Eclipse highlighted this statement in red and did not like it. Why?

My first thought was because of that problem that you can't compare strings with each other. The "==" and "!=" operators are mathematical comparisons that you can only use on primitives like ints, whereas for strings that operator will examine the underlying object in memory that stores the string; it won't examine the value.

But wait a minute, that can't be it. First of all, comparing strings is technically a valid argument...it will just usually return an inaccurate result. Like if there were two strings "hello" and "hello" that pointed to two different objects, it will return "False" when the developer probably wanted it to return "True". 

Also, str.charAt(pos + 1)is actually a char, not a string, and chars are primitives, so it should be OK to use the "!=" on it.

The problem was that the second part of my comparison, " ", is a string, so I was comparing a char against a string which isn't ok. All I had to do to fix it was put the space sign in single quotes, since Java denotes chars with single quotes. Easy :)

The second bug came up as I tried to run the program. This is what the code looked like at that point:

import acm.program.*;
 
public class acronymBuilder extends ConsoleProgram {
    public void run(){
        String initialString = readLine("Enter a string you want to generate the acronym for:");
        String result = acronym(initialString);
        println(result);
    }
    
    private String acronym(String str) {
        String result = str.substring(0, 1); 
        int pos = str.indexOf(' '); 
        while (pos != -1) {
            if (str.charAt(pos + 1) != ' ') { 
                result += str.substring(pos + 1, pos + 2); 
                pos = str.indexOf(' ', pos + 1); //Finds the next space sign
            }
        } 
    return result;
    }
}
When I ran the code, it compiled and I input the string "ne**s****w". (There were no "*" signs really, I just used them to demonstrate) where spaces were. When I hit "return", the program didn't print anything! Why?

At first I thought there was an unclosed loop or something, but then I realized: I had inserted an "if" statement checking for if the character following the space sign is NOT another space, but I didn't tell the program what to do if that following character WAS a space! The direction to move on to the next space sign (ie "pos = str.indexOf(' ', pos + 1)" was inside the new "if" statement! Once I adjusted the stuff in my loops I was fine.

Strange though-- on that second bug, my return statement WAS outside the "if" statement, and I had already initiated "result", so why didn't my program atleast print the first character...?

4 comments:

  1. The same in Visual Basic (LibreOffice)
    function acronym(str as String) as String
    dim result as string, pos as integer
    result = mid(str, 1, 1)
    pos = instr(str, " ")
    do while pos <> 0
    if mid(str, pos + 1, 1) <> " " then
    result = result + mid(str, pos + 1, 1)
    pos = instr(pos + 1, str, " ")
    end if
    loop
    acronym = result
    end function

    ReplyDelete
  2. Oops, one fix:

    function acronym(str as String) as String
    dim result as string, pos as integer
    result = mid(str, 1, 1)
    pos = instr(str, " ")
    do while pos <> 0
    if mid(str, pos + 1, 1) <> " " then
    result = result + mid(str, pos + 1, 1)
    end if
    pos = instr(pos + 1, str, " ")
    loop
    acronym = result
    end function

    ReplyDelete