Full Header Image

Chapter 12: Advanced String Concepts

Strings have been used throughout this series. By now, you should understand that strings hold a series of characters. In this chapter, you will learn more about Strings, how they are structured, how they may be broken down or manipulated, and how to search them. You will also create an algorithm yourself that searches and replaces text in Strings.

At the end of this chapter, you will create a program that counts the number of words in a String.

Structure of Strings

Strings Are Arrays of Characters

Strings are very similar to arrays. You could think of them like an array of characters, where the first index (zero) is the first character in the string. Recall that a String object contains multiple characters and a char object contains a single character. In fact, you may create a String from an array of chars, and explode a String into an array of chars.

String from char array

//Create an array of chars
char[] arrayOfChars = new char[5];
arrayOfChars[0] = 'h';
arrayOfChars[1] = 'e';
arrayOfChars[2] = 'l';
arrayOfChars[3] = 'l';
arrayOfChars[4] = 'o';

//Create a String from an Array of chars
String myString = new String(arrayOfChars);

//Print it out
System.out.print(myString);Code language: JavaScript (javascript)
Terminal
hello

Concatenation

Recall that concatenation is when two or more Strings are combined into one.

String a = "hello, ";
String b = "world.";
String c = a + b;
System.out.print(c);Code language: JavaScript (javascript)
Terminal
hello, world.

Substrings

What if you want to extract a section of a String from a larger String? To do this, you may use the .substring(start, end) method. Where start is the index of the String we are starting at, and end is the index we’re going up to. The substring will contain the characters between these two indices.

The example below takes a substring of the message “hello, world.” It extracts the substring “world” from the larger String.

String myString = "hello, world.";
String anotherString = myString.substring(7, 12);
System.out.println(anotherString);Code language: JavaScript (javascript)
Terminal
world

Note in the above example, the character at index 7 is ‘w’ and the character at index 12 is ‘.’ It starts at the first index, and goes up to, but not including the last index. The ‘d’ in world is actually at index 11, not 12.

Substring Problem

Examine the following code. What arguments go in the second line to produce the word “apple”?

String myString = "The apple is blue.";
String substring = myString.substring();
System.out.println(substring);Code language: JavaScript (javascript)
View Solution

String Length

Just as you can get the length of an Array using .length or an ArrayList using .size(), you may find the length of a String using .length().

//Create a string
String myString = "Hello! I like ice cream.";
System.out.printf("The length of this String is: %d", myString.length());Code language: JavaScript (javascript)
Terminal
The length of this String is: 24

Characters

Recall that characters, using the ‘char’ datatype, represent a 16 bit Unicode character.

//create a character "a"
char character = 'a';
System.out.println(character);

//increment the value of the char by 1
character ++;
//print the result
System.out.println(character);Code language: JavaScript (javascript)
Terminal
a
b

Since characters are really just numbers, and the Unicode number for ‘a’ is 97, when the char above is incremented by 1, it becomes 98. 98 is the Unicode number for the character ‘b’.

If you want to find the decimal corresponding to a particular character in Unicode, you may cast the char to an int.

//create a character "a"
char character = 'a';

//what's the unicode decimal for this char
System.out.println((int)character);Code language: JavaScript (javascript)
Terminal
97

toCharArray

You may use the toCharArray() method on any String to convert it into an array of chars.

//Create a string
String test = "Puppies are super cute.";

//Convert it to an array of chars
char[] charArray = test.toCharArray();

//Print out the first, second, third index of the array
System.out.println(charArray[0]);
System.out.println(charArray[1]);
System.out.println(charArray[2]);Code language: JavaScript (javascript)
Terminal
P
u
p

Now, you can freely convert Strings to arrays of chars, and arrays of chars back into Strings.

//Create a string
String test = "Puppies are super cute.";

//Convert it to an array of chars
char[] charArray = test.toCharArray();

//Turn it back into another String
String anotherString = new String(charArray);Code language: JavaScript (javascript)

When you turn a String into an array of chars, it’s said that you are exploding the String.

Case Study: Basic Encryption

Given our knowledge of Strings, Characters, Arrays, and Unicode, we’re going to create a program that encrypts and decrypts messages.

How it Works

The program will first ask the user if they want to 1) encrypt or 2) decrypt a message.

If the user opts to encrypt a message, they will be asked to type a message to encrypt. After the message is typed, the user will create a “key” for the encryption. The key will be a number between 1 and 100.

The program will then encrypt the message by incrementing the Unicode value of each character in the string by the key value entered. It will then print out the encrypted message to the console.

If the user opts to decrypt the message, they will paste the encrypted message, enter the key, and the decrypted message will be generated by decreasing the Unicode value of each character in the string entered. Thus recovering the original message.

Tip: Remember to write and test the code yourself. Do not just copy/paste it.

Basic Template

To get started, let’s lay out the options and set up the scanner.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {

        //Scanner
        Scanner input = new Scanner(System.in);

        //User choose option
        System.out.println("Would you like to:");
        System.out.println("1) Encrypt a message");
        System.out.println("2) Decrypt a message");

        int option = input.nextInt();
		//clear scanner
        input.nextLine();

        if(option == 1){
            //TODO Encryption code here

        }
        else if(option == 2){
            //TODO Decryption code here
        }

        input.close();
        System.out.println("Program ending. Run the program again to encrypt/decrypt a message.");

    }

	 /**
     *
     * @param message - the message being encrypted/decrypted
     * @param key - the number to shift up or down
     * @return - the encrypted or decrypted message
     */
	public static String shiftString(String message, int key){
		//TODO write a method that shifts each character in the String by a set number
	}
}Code language: JavaScript (javascript)

The Encryption Code

To encrypt the message, we need to ask the user for a message and a key.

if(option == 1){
    //Get the message to encrypt
    System.out.println("Enter a message to encrypt.");
    String message = input.nextLine();

    //Get an encryption key
    System.out.println("Please enter a key number between 1 and 100:");
    System.out.println();
    int key = input.nextInt();
    System.out.println("You have selected a key of [" + key + "].");

    //Print out the encrypted message
    System.out.println("Here is your encrypted message:");
    System.out.println(shiftString(message, key));

}Code language: JavaScript (javascript)

The shiftString method will increase each Unicode character by a set number.

The shiftString method

This method converts the message into a char array, increments them by the key, then returns the new String.

public static String shiftString(String message, int key){
    //convert the string to an array of chars
    char[] chars = message.toCharArray();
    //iterate through the array
    for(int i = 0; i < chars.length; i++){
        //increment by the key
        chars[i] += key;
    }
    //convert back to string
    return new String(chars);

}Code language: JavaScript (javascript)

Test it

Now, we need to test it. The easiest way to test it is to encrypt a message with a key of “1” which should simply shift the letters up by one.

Terminal
Would you like to:
1) Encrypt a message
2) Decrypt a message
1
Enter a message to encrypt.
hello
Please enter a key number between 1 and 100:

1
You have selected a key of [1].
Here is your encrypted message:
ifmmp

With a key of 1, each letter in “hello” is now the next letter. Char ‘i’ comes after ‘h’, ‘f’ after ‘e’, ‘m’ after ‘l’, and ‘p’ after ‘o’. The Unicode characters have been shifted up once. It’s working properly.

Decrypting

Now, we need to write the code to decrypt a message. This will work just like encryption, but instead, we’ll use a negative key. This will decrypt the message.

else if(option == 2){
    //Get the message to decrypt
    System.out.println("Paste a message to decrypt.");
    String message = input.nextLine();

    //Get an encryption key
    System.out.println("Please enter the key number:");
    System.out.println();
    int key = input.nextInt();

    //Print out the decrypted message
    System.out.println("Here is your decrypted message:");
    System.out.println(shiftString(message, -key));
}Code language: JavaScript (javascript)

Finally, test it out using the key and encrypted message from earlier.

Terminal
Would you like to:
1) Encrypt a message
2) Decrypt a message
2
Paste a message to decrypt.
ifmmp
Please enter the key number:

1
Here is your decrypted message:
hello
Program ending. Run the program again to encrypt/decrypt a message.

Remember: Test your program multiple times with multiple inputs to make sure it’s working properly.

Click the button below to view the entire program, if you had any issues.

View Complete File

Case Study: Find & Replace

Another common operation you may need to do with Strings is finding a set of characters. If the characters are found, we can find the index it occurs at or replace it with something else. The String class contains methods you may use to quickly complete these operations, but for demonstration, we’ll first look at completing these algorithms from scratch.

Find Example

Look at the following string of text.

String s = "My very educated mother just served us nine pears.";Code language: JavaScript (javascript)

Now let’s say we want to confirm that the word “nine” exists somewhere in that string. How can we programmatically figure this out?

First, we must iterate through each character in the String and see if an ‘n’ exists. If it does, we need to see if it’s followed by an ‘i’, then an ‘n’ and an ‘e’. If the first n isn’t followed by an ‘i’, the program should continue searching for another ‘n’ until it reaches the end of the String.

Create a new project. Add the String to be tested and a method to search it.

public class Main {
    public static void main(String[] args) {

        //Test String
        String s = "My very educated mother just served us nine pears.";

    }

    /**
     *
     * @param keyword - the string we are searching for
     * @param search - the string being searched
     * @return - true if it was found, false if not
     */
    public static boolean keywordExists(String keyword, String search){

        return false;
    }
}Code language: JavaScript (javascript)

The method that does all the work here is the keywordExists method. It has two parameters – a String containing the keyword we’re looking for, and the String being searched. It returns true if the entire keyword was found, and false if not. To find if “nine” exists in String s, it would work like this:

if(keywordExists("nine",s)){
    System.out.println("Found 'nine' in String s");
}Code language: JavaScript (javascript)

Now, let’s implement the keywordExists method.

To begin, we will break both Strings down into arrays of chars. We’ll also create a boolean that keeps track of if a match is being found.

public static boolean keywordExists(String keyword, String search){

        //Break both Strings down into arrays of chars
        char[] searchArray = search.toCharArray();
        char[] keywordArray = keyword.toCharArray();

        //keep track of if a match was found
        boolean foundMatch = false;
	}
}Code language: JavaScript (javascript)

Next, we need to find if the first character in the keyword matches any of the characters in the String being searched. So iterate through each character in the search String, and check if it matches the first character in the keyword String. This loop will run from index 0 of the search String to the last possible index of the search String where an exact match can be found. For example, if I’m searching for the keyword “apple” in the String “Martin has an apple”, the last possible index “apple” can start at is 5 spaces from the end. So there’s no need to check if there’s an ‘a’ in the last 4 spaces.

public static boolean keywordExists(String keyword, String search){

        //Break both Strings down into arrays of chars
        char[] searchArray = search.toCharArray();
        char[] keywordArray = keyword.toCharArray();

        //keep track of if a match was found
        boolean foundMatch = false;

        //Iterate through searchArray, up until the last possible point the keyword may exist at.
        //keywordArray.length is subtracted from searchArray.length, because beyond a certain point keywordArray will no longer fit at the end of searchArray
        for(int i = 0; i <= searchArray.length - keywordArray.length; i++){
            //check if this char is the same as the first char we're looking for
            if(searchArray[i] == keywordArray[0]){
                //we have found the first character, we must now check if the following characters are equal
                foundMatch = true;
            }
        }
}Code language: JavaScript (javascript)

After we find a match of the first character in the keyword, we must see if the following characters in the keyword match the following characters in the String being searched. To do this, we must loop through each following index of the keyword (indices 1 through the end of the array), and check that against each following character in the search String (whatever index the first match was found followed by however many indices are in the keyword array).

If any of these do not match exactly, we know a match has NOT been found and set foundMatch to false. If we get through this entire check, and foundMatch is still true, we know we have found an exact match.

Once an exact match has been found, the entire method returns true. This ends the method and no further checks are performed.

If we get to the end of the search array without finding a single match, then the method returns false at this point.

The completed method looks like this:

public static boolean keywordExists(String keyword, String search){

        //Break both Strings down into arrays of chars
        char[] searchArray = search.toCharArray();
        char[] keywordArray = keyword.toCharArray();

        //keep track of if a match was found
        boolean foundMatch = false;

        //Iterate through searchArray, up until the last possible point the keyword may exist at.
        //keywordArray.length is subtracted from searchArray.length, because beyond a certain point keywordArray will no longer fit at the end of searchArray
        for(int i = 0; i <= searchArray.length - keywordArray.length; i++){
            //check if this char is the same as the first char we're looking for
            if(searchArray[i] == keywordArray[0]){
                //we have found the first character, we must now check if the following characters are equal
                foundMatch = true;
                //loop through the following characters in keywordArray
                for(int x = 1; x < keywordArray.length; x++){
                    //if the next element in searchArray does not match the next element in keywordArray, it is not a match
                    if(searchArray[i+x] != keywordArray[x]){
                        foundMatch = false;
                        break;
                    }
                }
            }
            //if we got through all the checks without foundMatch being set to false, we know a complete match has been found and may return true
            if (foundMatch == true){
                return true;
            }
        }
        //if we get to this point, we have searched the entire array without finding any exact matches
        return false;
    }Code language: JavaScript (javascript)

Finally, we need to test the method to make sure it works. Create some strings of sentences and select some keywords to search for. The keywords should be taken from the beginning, middle, and end of the search String. This way, we test that the foundMatch method works in multiple locations.

Here is the method I created to test the code.

public static void main(String[] args) {

    //Test String
    String s = "My very educated mother just served us nine pears.";

    //Should print true because nine is in the search string
    System.out.println(keywordExists("nine", s));

    //Should print true
    System.out.println(keywordExists("pears.", s));

    //Should print false since there is no 'my' only a 'My'
    System.out.println(keywordExists("my", s));

    //Should print true
    System.out.println(keywordExists("My", s));

}Code language: PHP (php)

Based on the order I called keywordExists, it should print true, true, false, true, in that order.

Terminal
true
true
false
true

The output is what I expected. The method appears to be working properly.

Modify The Code

Directions: Create a new method called firstMatchedIndex, which returns the index at which the first keyword match was found in the String being searched as an int. If no matches were found, it should return “-1”. You may do this using the same code as the keywordExists method above, with slight modifications.

Template

/**
 * @param keyword - the string we are searching for
 * @param search - the string being searched
 * @return - the first index at which a match was found in search string
 */
public static int firstMatchedIndex(String keyword, String search){

    //return -1 if no matches were found
    return -1;
}Code language: JavaScript (javascript)

Here is some test code and the expected output once you have successfully implemented the method.

Test Code

public static void main(String[] args) {

    //Test String
    String s = "My very educated mother just served us nine pears.";

    //Should return 0, since My starts at index 0 in s
    System.out.println(firstMatchedIndex("My", s));

    //Should return 3, since "very" begins at index 3 of s
    System.out.println(firstMatchedIndex("very", s));

    //Should return -1, since this word is not in the search string
    System.out.println(firstMatchedIndex("father", s));

}Code language: PHP (php)
Terminal
0
3
-1
View Sample Solution

Replace

Now that we’ve created a method which finds the first occurrence of a shorter String in a longer String, we’re going to create a method that replaces the found String with another String.

The method will have three parameters, the keyword we’re searching for, the String being searched, and the String we’re replacing the keyword with.

/**
     *
     * @param keyword - word we're looking for
     * @param replace - what it's being replaced with
     * @param search - the string being searched
     * @return - the new version of the string being searched
     */
    public static String findReplace(String keyword, String replace, String search){
}Code language: JavaScript (javascript)

The method will first check if the keyword is in the search String and determine its location using the previously created methods. If nothing was found, there is nothing to replace, and it will just return the original search string.

There are more efficient ways of handling this, but for demonstration, we’ll keep things as simple as possible. The contents of the original String will be broken into an array of chars, and a new array of chars will be created which contains just the right amount of space to hold the replacement word. The first section of the original array, up until the first index found of the keyword String, will be copied into the new array. Then, the contents of the “replace” string will be added. Finally, anything coming after the word we’re replacing from the original array will be added at the end.

Remember, we’re only going to worry about replacing the first instance of the found word.

Once the start, replacement, and end sections have been added to the new char array, we can return it as a String.

Stop: Based on the above explanation, I’d encourage you to try to complete this method by yourself before continuing to read on below.

Get started by checking if the keyword exists. Then, explode the original String and the replacement String.

public static String findReplace(String keyword, String replace, String search){
    //make sure there's something to replace
    if(!keywordExists(keyword, search)){
        //if the keyword does not exist, return the original String
        return search;
    }

    //get the first index
    int firstIndex = firstMatchedIndex(keyword, search);

    //explode strings
    char[] originalString = search.toCharArray();
    char[] replacementWords = replace.toCharArray();Code language: JavaScript (javascript)

Next, we need to determine how long the new array has to be. For example, if we’re searching for the word “hello” and we’re replacing it with the word “hey” then the new String has to have 2 elements fewer than the original. If we’re searching for the word “dog” and replacing it with the word “wolf,” we need to make the new array 1 element larger than the original.

To achieve this, find the difference between the keyword and the replace String. Then create a new array of chars equal to the original array in length, plus or minus the difference.

int lengthToAdd = 0; //the amount of extra space we need to allocate
lengthToAdd = replace.length() - keyword.length();

//create a new array, which will eventually become the "replaced" string
char[] replacementString = new char[originalString.length + lengthToAdd];Code language: JavaScript (javascript)

Now that we have an empty replacementString ready to hold our new String, we can start adding to it. Create a loop that goes from 0 to the first index we found. This is everything that comes before the replacement. Copy all these values into the new array.

for(int i = 0; i < firstIndex; i++){
    replacementString[i] = originalString[i];
}Code language: HTML, XML (xml)

Next, insert the replacement word using another loop. It should be added starting at the first index found previously.

//insert the replacement word
for(int i = 0; i < replacementWords.length; i++){
    replacementString[firstIndex + i] = replacementWords[i];
}Code language: JavaScript (javascript)

Finally, add the remaining part of the original String. Then return the new String.

//insert everything that comes after the replaced word
for(int i = firstIndex + keyword.length(); i< originalString.length; i++) {
    replacementString[i + lengthToAdd] = originalString[i];
}
//return the string
return new String(replacementString);Code language: JavaScript (javascript)

Finally, write some test code to the main method make sure it works.

String s = "My very educated mother just served us nine pears.";
String x = findReplace("educated", "smart", s);

System.out.println(x);

s = "My very educated mother just served us nine pears.";
x = findReplace("pears", "pineapples", s);

System.out.println(x);Code language: JavaScript (javascript)
Terminal
My very smart mother just served us nine pears.
My very educated mother just served us nine pineapples.

For reference, you may access the completed file below.

View Completed Project

Built-in Find/Replace Methods

Java has find/replace methods built in. They’re more efficient than the methods created above and contain additional functionality. Now that you understand some of the logic behind how they work, use these instead.Find/Replace

//Test String
Strings = "My very educated mother just served us nine pears.";

//replace pears with pineapples
String x = s.replace("pears", "pineapples");
System.out.println(x);

//replace the first Cow with Cattle
s = "Cow Chicken Cow Cow Chicken";
x =  s.replaceFirst("Cow", "Cattle");
System.out.println(x);

//replaceAll Cow with Cattle
s = "Cow Chicken Cow Cow Chicken";
x =  s.replaceAll("Cow", "Cattle");
System.out.println(x);Code language: JavaScript (javascript)
Terminal
My very educated mother just served us nine pineapples.
Cattle Chicken Cow Cow Chicken
Cattle Chicken Cattle Cattle Chicken

Other Useful Finder Methods

Below, I summarize some other String search methods you may find useful.

.endsWith()

The .endsWith() method may be used to check if a String ends with a particular set of characters. It returns a boolean (true or false). This may be useful if you’re checking for a certain file extension.

String filename = "c:\users\kevin\desktop\myfile.txt";
if(filename.endsWith(".txt")){
    System.out.println("This is a valid text file.");
}Code language: JavaScript (javascript)
Terminal
This is a valid text file.

.startsWith()

This works the same as endsWith, except it checks the start of the String.

.contains()

The .contains() method can be used to check if a String contains another String or char. This is like the keywordExists() method we created earlier.

String aString = "Hello, world.";
if (aString.contains("w")){
    System.out.println("There's a w in this String.");
}Code language: JavaScript (javascript)
Terminal
There's a w in this String.

indexOf

The .indexOf() method allows you to get the numerical index of the first instance of a located String within a larger String. It works similarly to the firstMatchedIndex method created earlier in this chapter.

String s = "Hello, World.";
int indexOfWorld = s.indexOf("World");

//W starts at index 7 of the String, should print 7
System.out.println(indexOfWorld);Code language: JavaScript (javascript)
7

The .lastIndexOf() method allows you to get the index of the first character of the last instance of a found String within a larger String.

String s = "Hello, World. World. World.";
int indexOfWorld = s.indexOf("World");
int lastIndexOfWorld = s.lastIndexOf("World");
System.out.println("The first instance of World is at index " + indexOfWorld + " and the last is at " + lastIndexOfWorld + " in the given String.");Code language: JavaScript (javascript)
Terminal
The first instance of World is at index 7 and the last is at 21 in the given String.

charAt

The .charAt(idx) method returns the char at a certain index in a String.

String aString = "Hello, world.";
char aChar = aString.charAt(4);
System.out.println("The char at index 4 is: " + aChar);Code language: JavaScript (javascript)
Terminal
The char at index 4 is: o

Assignment: Word Counter

You have reached the end of this chapter. I hope you’ve followed along. If you haven’t, I’d encourage you to go back and try creating the find/replace algorithms yourself. In the next chapter, you will learn more about object-oriented design.

Word Counter Assignment

Directions: Create a method called getWordCount, which takes a String as a parameter and returns an int. The method checks the given String, counts the amount of words in it, and returns the number of words in the String.

  • Rules
    • The program must only count words (made up of standard 26 letters).
    • The program must work on upper and lower case words.
    • Numbers or symbols by themselves do not count as words.
    • Each word must start and end with a letter.
    • Single character words are permitted.
    • The program does not check spelling. “garbagoo” is counted as a word. The letter “Z” by itself is a word. Any set of alphabetical characters is counted as a word.

Below is a template to get started.

public class Main {
    public static void main(String[] args) {

        //Test Code should print 2
        String a = "Hello, world.";
        System.out.println(getWordCount(a));

        //should print 5
        System.out.println(getWordCount("This string has five words."));

        //should print 9
        System.out.println(getWordCount(" The sound moo is the sound a cow    makes."));

        //should print 7
        System.out.println(getWordCount("A Z apple! banana a z zebra 12"));

    }

    public static int getWordCount(String s){

        //Your code here
        return -1;
    }
}Code language: JavaScript (javascript)

Suggested Methodology: Break the String down into an array of chars, iterate through each char with a loop, and check if each char is a letter (upper or lower case). When a letter is found, a word has been found. Count this as one word. Continue until you find something that isn’t a letter, then when you find another letter, count it as another word.

Remember, you can get the numerical Unicode value for any char by casting it to an int. Upper case letters have Unicode values from 65 to 90, and lower case from 97 to 122.

It may be helpful to create another method to check if a char is a letter or not. This is up to you.

View Solution
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments