Lesson 8 - Strings in Java - Working with single characters

Java Basic constructs Strings in Java - Working with single characters

In the last lesson, Arrays in Java, we learned to work with arrays. If you noticed some similarities between arrays and strings, then you were absolutely onto something. For the others, it may be a surprise that a String is essentially an array of characters (chars) and we can work with it like so. We use the charAt(x) method to access characters in a string, where the x parameter is the character index (0 based).

First, we'll check out how it works by simply printing the character at the given positions:

String s = "Hello ICT.social";
System.out.println(s);
System.out.println(s.charAt(2));

The output:

Console application
Hello ICT.social
l

It may be disappointing that characters at the given positions are read-only in Java. Of course, there is a way to change them, but we'll go over it later. For now, we'll be reading characters.

Character occurrence in a sentence analysis

Let's write a simple program that analyzes a given sentence for us. We'll search for the number of vowels, consonants and non-alphanumeric characters (e.g. space or !).

We'll hard-code the input string in our code, so we won't have to write it again every time. Once the program is complete, we'll replace the string with scanner.nextLine(). We'll iterate over characters using a loop. I should start out by saying that we won't focus as much on program speed here, we'll choose practical and simple solutions.

First, let's define vowels and consonants. We don't have to count non-alphanumeric characters since it'll be the string length minus the number of vowels and consonants. Since we don't want to deal with the case, uppercase/lower­case, of the letters, we'll convert the entire string to lowercase at the start. Let's set up variables for the individual counters, also, because it is a more complex code, we'll add in comments.

// the string that we want to analyze
String s = "A programmer gets stuck in the shower because the instructions on the shampoo were: Lather, Wash, and Repeat.";
System.out.println(s);
s = s.toLowerCase();

// Counters initialization
int vowelsCount = 0;
int consonantsCount = 0;

// definition of character groups
String vowels = "aeiouyaeeiouuy";
String consonants = "bccddfghjklmnpqrrssttvwxzz";

// the main loop
for (char c : s.toCharArray()) {

}

First of all, we prepare the string and convert it to lowercase. Then, we reset the counters. For the definition of characters groups, we only need ordinary Strings. The main loop iterates over each character in the String s. In order to be able to iterate over the characters, we need to convert the String to an array of characters first. In the introduction, we said that Strings are basically arrays of characters, however, they still differ a bit. It has some extra things and lacks some things, like the ability to be iterated using loops. So we call the toCharArray() method on the s String which returns the real array of its characters. In each iteration of the loop the variable c will contain the current character.

Now let's increment the counters. For simplicity's sake, I'll focus on the loop instead of rewriting the code repeatedly:

// the main loop
for (char c : s.toCharArray()) {
        if (vowels.contains(String.valueOf(c))) {
                vowelsCount++;
        }
        else if (consonants.contains(String.valueOf(c))) {
                consonantsCount++;
        }
}

The contains() method on a String is already known to us. As a parameter, it takes a substring. Unfortunately, it doesn't accept characters, so we need to convert c to a String first. There is a valueOf() method for that. Firstly, we try to find the character c from our sentence in the String vowels and possibly increase their counter. If it's not included in vowels, we look in consonants and possibly increase their counter.

Now all we're missing is the printing, displaying text, part at the end:

System.out.println("Vowels: " + vowelsCount);
System.out.println("Consonants: " + consonantsCount);
System.out.println("Non-alphanumeric characters: " + (s.length() - (vowelsCount + consonantsCount)));

Console application
A programmer gets stuck in the shower because the instructions on the shampoo were: Lather, Wash, and Repeat.
Vowels: 33
Consonants: 55
Non-alphanumeric characters: 21

That's it, we're done!

The ASCII value

Maybe you've already heard about the ASCII table. Especially, in the MS-DOS era when there was practically no other way to store text. Individual characters were stored as numbers of the byte datatype, so of a range from 0 to 255. The system provided the ASCII table which had 256 characters and each ASCII code (numerical code) was assigned to one character.

Perhaps you understand why this method is no longer as relevant. The table simply could not contain all the characters of all international alphabets, now we use Unicode (UTF-8) encoding where characters are represented in a different way. In Java, we have the option to work with ASCII values of individual characters. The main advantage is that the characters are stored in a table next to each other, alphabetically. For example, at position 97 we can find "a", at 98 "b" etc. It is the same with numbers, but unfortunately, the accent characters are messed up.

Now, let's convert a character into its ASCII value and vice versa create the character according to its ASCII value. Btw, we use a special \n sequence which causes a line to break.

char c; // character
int i; // ordinal (ASCII) value of a character
// conversion from text to ASCII value
c = 'a';
i = (int)c;
System.out.printf("The character %c was converted to its ASCII value of %d\n", c, i);
// conversion from an ASCII value to text
i = 98;
c = (char)i;
System.out.printf("The ASCII value of %d was converted to its textual value of %c", i, c);

These conversions are called type casts, which we'll get into later on.

The Caesar cipher

Let's create a simple program to encrypt text. If you've ever heard of the Caesar cipher, then you already know exactly what we're going to program. The text encryption is based on shifting characters in the alphabet by a certain fixed number of characters. For example, if we shift the word "hello" by 1 character forwards, we'd get "ifmmp". The user will be allowed to select the number of character shifts.

Let's get right into it! We need variables for the original text, the encrypted message, and the shift. Then, we need a loop iterating over each character and printing an encrypted message. We'll also have to hard-code the message defined in the code, so we won't have to write it over and over during the testing phase. After we finish the program, we'll replace the contents of the variable with the scanner.nextLine() method. The cipher doesn't work with accent characters, spaces and punctuation marks. We'll just assume the user will not enter them. Ideally, we should remove accent characters before encryption, as well as anything except letters.

// variable initialization
String s = "blackholesarewheregoddividedbyzero";
System.out.println("Original message: " + s);
String message = "";
int shift = 1;

// loop iterating over characters
for (char c : s.toCharArray()) {

}

// printing
System.out.println("Encrypted message: " + message);

We will now move into the loop, we'll cast the character c to its ASCII value, its ordinal value, increase the value by however many shifts and cast it back to the character. This character will be added to the final message:

int i = (int)c;
i += shift;
char character = (char)i;
message += character;

Console application
Original message: blackholesarewheregoddividedbyzero
Encrypted message: cmbdlipmftbsfxifsfhpeejwjefecz{fsp

Let's try it out! The result looks pretty good. However, we can see that the characters after "z" overflow to ASCII values of other characters ("{" in the picture). Therefore, the characters are no longer just alphanumeric, but other nasty characters. Let's set our characters up as a cyclical pattern, so the shifting could flow smoothly from "z" to "a" and so on. We'll get by with a simple condition that decreases the ASCII value by the length of the alphabet so we'd end back up at "a".

int i = (int)c;
i += shift;
// overflow control
if (i > (int)'z') {
        i -= 26;
}
char character = (char)i;
message += character;

If i exceeds the ASCII value of 'z', we reduce it by 26 characters (the number of characters in the English alphabet). The -= operator does the same as we would do with i = i -26. It's simple and our program is now operational. Notice that we don't use direct character codes anywhere. There's an (int)'z' in the condition even though we could write 122 there directly. I set it up this way so that our program is fully encapsulated from explicit ASCII values, so it'd be clearer how it works. Try to code the decryption program as practice for yourself.

In the next lesson, Strings in Java - Split, we'll see that there are still a couple more things we haven't touched base on that strings can do. Spoiler: We'll learn how to decode "Morse code".


 

Download

Downloaded 41x (33.33 kB)
Application includes source codes in language Java

 

 

Article has been written for you by David Capka
Avatar
Do you like this article?
2 votes
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn College The author learned IT at the Unicorn College - a prestigious college providing education on IT and economics.
Thumbnail
Previous article
Arrays in Java
Thumbnail
All articles in this section
Java basic constructs
Activities (7)

 

 

Comments

Avatar
Sajjad Sajjad Khan:4. September 1:13

it very hard exercise really

 
Reply 4. September 1:13
To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

1 messages from 1 displayed.