Working with text
Problem
The code is right, but it does not work
The shop gives 10% off with the code SUMMER10. A customer copies it from the ad, but types it in lowercase and puts a space in front by accident:
Scanner in = new Scanner(System.in);String code = in.nextLine();if (code.equals("SUMMER10")) { System.out.println("10% off");} else { System.out.println("Invalid code");} summer10Invalid codeTo a person, the code is the same. To the program, summer10 and SUMMER10 are different texts: the first has one more character, and the letters are different. You need to be able to look inside a text and fix it.
The idea
Text is a sequence of characters
Text is characters placed one after another: letters, digits, spaces, signs. Each character has an index, like in an array. The first one has index 0.
String code = "SUMMER10";System.out.println(code.length());System.out.println(code.charAt(0));System.out.println(code.charAt(code.length() - 1));8S0code.length()is the number of characters.code.charAt(0)is the character with index 0. The last character has indexlength() - 1.
A single character has its own type: char. You write it in single quotes: 'S', '0', ' '. Text goes in double quotes: "S" is a text with one character, not a char.
Watch the parentheses: for text it is length(), with parentheses, because it is a method. For an array it is length, without parentheses.
See it
Character by character
How many digits are in the phone number? You loop through the indexes from 0 to the last one and look at each character:
String phone = "0888 123 456";int digits = 0;for (int i = 0; i < phone.length(); i++) { char c = phone.charAt(i); if (c >= '0' && c <= '9') { digits++; }}System.out.println("Digits: " + digits);Digits: 10c >= '0' && c <= '9' works because every character is really a number: its code in the character table. The digits from '0' to '9' have consecutive codes, and so do the letters from 'a' to 'z'. That is why characters compare like numbers.
More precisely, if you are curious
- There are ready-made methods for checks like these:
Character.isDigit(c),Character.isLetter(c),Character.isUpperCase(c),Character.isLowerCase(c). They also know letters outside English, likeé. - You get the code of a character with a cast:
(int) 'A'is 65. The other way,(char) 66is'B'. That is why'a' + 1is the number 98, not the letterb. - Without an index:
for (char c : phone.toCharArray())goes through the characters, the way for-each goes through an array.
Try it
Which character?
What will the program print?
String word = "Invoice";System.out.println(word.charAt(3));System.out.println(word.length());The indexes are I 0, n 1, v 2, o 3. The character with index 3 is the fourth one: "o". The length is the count of all the characters, 7. The last index is 6.
The idea
The methods of text
Text comes with ready-made methods: actions you call with a dot after the text. Here is the fix for the promo code:
String code = " summer10";String clean = code.trim().toUpperCase();System.out.println("[" + clean + "]");System.out.println(clean.equals("SUMMER10"));[SUMMER10]truetrim() removes the spaces at the front and at the back. toUpperCase() makes all the letters uppercase. Methods can be chained one after another: the first returns a text, and the second is called on it.
A few more, on an email address:
String email = "ivan.petrov@mail.bg";System.out.println(email.contains("@"));System.out.println(email.indexOf("@"));System.out.println(email.substring(0, email.indexOf("@")));System.out.println(email.replace(".", " "));System.out.println(email.endsWith(".bg"));true11ivan.petrovivan petrov@mail bgtrue| Method | What it does |
|---|---|
contains(x) |
whether x is inside |
indexOf(x) |
the index where x first appears (-1 if it is not there) |
substring(a, b) |
a part of the text |
replace(x, y) |
every x is replaced with y |
startsWith(x), endsWith(x) |
whether it starts (ends) with x |
toLowerCase() |
all letters lowercase |
More precisely, if you are curious
substring(a, b) takes the characters from index a to index b, without b. Their count is b - a. With only one argument it takes everything to the end:
String date = "2026-10-24";System.out.println(date.substring(5, 7));System.out.println(date.substring(8));1024The idea
Text does not change
There is one quirk that confuses everyone at first:
String name = "maria";name.toUpperCase();System.out.println(name);name = name.toUpperCase();System.out.println(name);mariaMARIAThe second line does nothing you can see. toUpperCase() does not change name. It makes a new text in uppercase and returns it. Nobody stores it, and it is lost.
Once created, a text cannot be changed. It is called immutable. Every method that "changes" a text actually returns a new one. To keep it, you assign it: name = name.toUpperCase();.
String name = "maria";name.toUpperCase();System.out.println(name);name = name.toUpperCase();System.out.println(name);Step by step, in words
- name holds the text "maria": 5 characters with indexes from 0 to 4.
- toUpperCase() does not touch "maria". It makes a new text, "MARIA".
- Nobody stores the new text, and it is lost.
- name still holds "maria", and that is what gets printed.
- Another new text, "MARIA", but now = stores it in name. The old "maria" is dropped.
- Now name holds "MARIA".
More precisely, if you are curious
- That is why
+=on text in a long loop is slow: every round makes a new text and copies everything so far. For hundreds of thousands of appends there isStringBuilder, an object that can be changed. We will see it in the module "Text and files".
Try it
Find the bug
The user types their email with uppercase letters and spaces. The program should clean it up and let them in, but it says "No such user.". Which line has the bug?
Pick the line with the bug.
email.trim(); returns a new text without the spaces, but it is not stored anywhere. email still has the spaces. The fix is email = email.trim();, just like on line 2.
The idea
Text in parts
Often a text holds several things, separated by a sign: items with a comma, words with a space. split splits it into parts and returns an array of texts:
String list = "milk,bread,eggs,cheese";String[] items = list.split(",");System.out.println("Items: " + items.length);for (int i = 0; i < items.length; i++) { System.out.println((i + 1) + ". " + items[i]);}Items: 41. milk2. bread3. eggs4. cheeseThe separator is not part of the pieces. From here on you work with a regular array: length, indexes, a loop.
This is also how you read a whole line of numbers from the keyboard: you split it and turn each part into a number. That is exactly what you were missing in the last lesson, on tables:
Scanner in = new Scanner(System.in);String[] parts = in.nextLine().split(" ");int sum = 0;for (String p : parts) { sum += Integer.parseInt(p);}System.out.println(sum);42 38 51 47 60238More precisely, if you are curious
splittakes a regular expression, not plain text. Most signs work as they are, but.means "any character": for a dot, writesplit("\\."). Regular expressions come in the module "Text and files".- Two spaces next to each other give an empty part
""between them.split(" +")(one or more spaces) solves that. - The opposite of
splitisString.join(", ", items): it joins the parts with a separator.
Try it
== or equals?
On the first card the promo code was compared with equals. Why not with ==, like numbers? The input is admin:
What will the program print?
Scanner in = new Scanner(System.in);String user = in.nextLine();System.out.println(user == "admin");System.out.println(user.equals("admin"));For texts, == does not compare the letters. It checks whether both sides are one and the same object in memory. The text read from the keyboard is a new object, and "admin" in the code is a different one. The letters are the same, the objects are not. equals compares the letters and says true.
The rule: in Java you always compare text with equals. If uppercase and lowercase don't matter, use equalsIgnoreCase.
More precisely, if you are curious
Sometimes == "works": "admin" == "admin" is true, because Java keeps identical texts from the code in one object. That is why the bug slips through a test with text from the code and only shows up with real input. Don't rely on it.
Exercise
Names and words
Solve the exercises in your editor. The text is read from the keyboard as a whole line.
1. The name backward. Read a name and print it from back to front. You go through the indexes from the last one down to 0 and append the characters to a new text.
MariaairaM2. Word count. Read a sentence and count the words. There can be more than one space between words, and there can be spaces at the start and at the end. Hint: a word starts where the character is not a space and the one before it is a space (or there is none before it).
Today is a holidayWords: 43. Palindrome. A palindrome reads the same from front to back and from back to front. Spaces and uppercase letters don't count. Remove the spaces, make the letters lowercase, and compare the first character with the last, the second with the one before last, and so on.
Never odd or evenIt is a palindromeCoffee with milkNot a palindromeExercise
Checks and counting
4. Strong password. Ask for a password until the user enters a strong one: at least 8 characters, at least one digit, one uppercase and one lowercase letter. After each weak password, say what is required. Hint: do-while and a check of each character with Character.isDigit, Character.isUpperCase, Character.isLowerCase.
coffeecoffee2026Coffee2026Password:Weak password: at least 8 characters, a digit, an uppercase and a lowercase letter.Password:Weak password: at least 8 characters, a digit, an uppercase and a lowercase letter.Password:Password accepted.More exercises
- Commas instead of spaces. Read a sentence and replace every space with a comma.
Tomorrow we leave for Varna→Tomorrow,we,leave,for,Varna. - The longest name. Read names separated by commas and print the longest one.
Ana,Kristina,Peter→Kristina. - Vowels as stars. Replace every vowel (a, e, i, o, u) with
*, whether it is uppercase or lowercase.I love coffee→* l*v* c*ff**. - Letter frequency. Count how many times each letter appears in the text, uppercase or lowercase alike. Hint: an array of 26 counters, one for each letter from
'a'to'z'. The index of the lettercisc - 'a'. Print only the letters that appear. - Character chart. Like the exercise above, but instead of the number, print that many stars:
a: ****. - How many times each word. Read a sentence and for each different word print how many times it appears. Hint: split it into words, and for each word check whether it was already counted earlier in the array.
- Sorting by length. Read words separated by spaces and print them from the shortest to the longest. Sort the array the way you sorted numbers, but compare the lengths.
- Sentence count. Count the sentences in a text: each one ends with
.,!or?. Watch out for...and?!: they end one sentence, not three. - Balanced brackets. Check whether the brackets in a text are balanced. With one kind of bracket, a counter is enough:
(adds 1,)subtracts 1. The counter must never drop below 0, and at the end it must be 0. With three kinds,(),[],{}, you need an array of characters in which you keep the open brackets, and a counter of how full it is: at a closing bracket, the last open one must be of the same kind.{[()]}is balanced,([)]is not.
Test