Към съдържанието
wannacode

Работа с текст

Проблем

Кодът е верен, а не минава

Магазинът дава 10% отстъпка с код SUMMER10. Клиентът го преписва от рекламата, но пише с малки букви и случайно слага интервал отпред:

Scanner in = new Scanner(System.in);
String code = in.nextLine();
if (code.equals("SUMMER10")) {
System.out.println("Отстъпка 10%");
} else {
System.out.println("Невалиден код");
}
Вход
summer10
Изход
Невалиден код

За човек кодът е същият. За програмата summer10 и SUMMER10 са различни текстове: първият има един символ повече, а буквите са други. Трябва да можеш да гледаш вътре в текста и да го оправяш.

Идеята

Текстът е поредица от символи

Текстът е подредени един след друг символи: букви, цифри, интервали, знаци. Всеки символ има индекс, като в масив. Първият е с индекс 0.

String code = "SUMMER10";
System.out.println(code.length());
System.out.println(code.charAt(0));
System.out.println(code.charAt(code.length() - 1));
Изход
8
S
0
  • code.length() е броят на символите.
  • code.charAt(0) е символът с индекс 0. Последният символ е с индекс length() - 1.

Един символ има свой тип: char. Пишеш го в единични кавички: 'S', '0', ' '. Текстът е в двойни: "S" е текст с един символ, а не char.

Внимавай със скобите: при текста е length(), с кръгли скоби, защото е метод. При масива е length, без скоби.

Виж го

Символ по символ

Колко цифри има в телефонния номер? Минаваш с цикъл през индексите от 0 до последния и гледаш всеки символ:

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);
Изход
Цифри: 10

c >= '0' && c <= '9' работи, защото всеки символ всъщност е число: кодът му в таблицата със символите. Цифрите от '0' до '9' имат поредни кодове, буквите от 'a' до 'z' също. Затова символите се сравняват като числа.

По-точно, за любопитните
  • За такива проверки има готови методи: Character.isDigit(c), Character.isLetter(c), Character.isUpperCase(c), Character.isLowerCase(c). Те знаят и кирилицата.
  • Кодът на символ получаваш с превръщане: (int) 'A' е 65. Обратно, (char) 66 е 'B'. Затова 'a' + 1 е числото 98, а не буквата b.
  • Без индекс: for (char c : phone.toCharArray()) минава през символите, както for-each минава през масив.

Пробвай

Кой символ?

Какво ще отпечата програмата?

String word = "Поръчка";
System.out.println(word.charAt(3));
System.out.println(word.length());
Отговор

Идеята

Методите на текста

Текстът идва с готови методи: действия, които викаш с точка след текста. Ето поправката на промо кода:

String code = " summer10";
String clean = code.trim().toUpperCase();
System.out.println("[" + clean + "]");
System.out.println(clean.equals("SUMMER10"));
Изход
[SUMMER10]
true

trim() маха интервалите отпред и отзад. toUpperCase() прави всички букви главни. Методите се нареждат един след друг: първият връща текст и върху него се вика вторият.

Още няколко, върху имейл адрес:

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"));
Изход
true
11
ivan.petrov
ivan petrov@mail bg
true
Метод Какво прави
contains(x) има ли го x вътре
indexOf(x) на кой индекс е x за първи път (-1, ако го няма)
substring(a, b) част от текста
replace(x, y) всяко x се заменя с y
startsWith(x), endsWith(x) започва ли (свършва ли) с x
toLowerCase() всички букви малки
По-точно, за любопитните

substring(a, b) взима символите от индекс a до индекс b, без b. Броят им е b - a. Само с един аргумент взима всичко до края:

String date = "2026-10-24";
System.out.println(date.substring(5, 7));
System.out.println(date.substring(8));
Изход
10
24

Идеята

Текстът не се променя

Има една особеност, която обърква всички в началото:

String name = "мария";
name.toUpperCase();
System.out.println(name);
name = name.toUpperCase();
System.out.println(name);
Изход
мария
МАРИЯ

Вторият ред не прави нищо видимо. toUpperCase() не променя name. Той прави нов текст с главни букви и го връща. Никой не го записва и той се губи.

Веднъж създаден, текстът не може да се промени. Казва се, че е неизменим (immutable). Всеки метод, който „променя“ текст, всъщност връща нов. За да го запазиш, присвояваш: name = name.toUpperCase();.

String name = "мария";
name.toUpperCase();
System.out.println(name);
name = name.toUpperCase();
System.out.println(name);
Стъпка по стъпка, с думи
  1. В name е текстът „мария“: 5 символа с индекси от 0 до 4.
  2. toUpperCase() не пипа „мария“. Прави нов текст „МАРИЯ“.
  3. Никой не записва новия текст и той се губи.
  4. В name си е „мария“ и то се отпечатва.
  5. Пак нов текст „МАРИЯ“, но сега = го записва в name. Старото „мария“ отпада.
  6. Сега в name е „МАРИЯ“.
По-точно, за любопитните
  • Затова += върху текст в дълъг цикъл е бавно: всяко завъртане прави нов текст и копира всичко досега. За стотици хиляди долепвания има StringBuilder, обект, който може да се променя. Ще го видим в модул „Текст и файлове“.

Пробвай

Намери грешката

Потребителят въвежда имейла си с главни букви и интервали. Програмата трябва да го изчисти и да го пусне, но казва „Няма такъв потребител.“. На кой ред е грешката?

Избери реда с грешката.

Идеята

Текстът на части

Често текстът съдържа няколко неща, разделени със знак: продукти със запетая, думи с интервал. split го разделя на части и връща масив от текстове:

String list = "мляко,хляб,яйца,сирене";
String[] items = list.split(",");
System.out.println("Продукти: " + items.length);
for (int i = 0; i < items.length; i++) {
System.out.println((i + 1) + ". " + items[i]);
}
Изход
Продукти: 4
1. мляко
2. хляб
3. яйца
4. сирене

Разделителят не влиза в частите. Оттук нататък работиш с обикновен масив: дължина, индекси, цикъл.

Така се чете и цял ред числа от клавиатурата: разделяш го и превръщаш всяка част в число. Точно това ти липсваше в миналия урок за таблиците:

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 60
Изход
238
По-точно, за любопитните
  • split получава регулярен израз, не обикновен текст. Повечето знаци работят направо, но . значи „всеки символ“: за точка пиши split("\\."). Регулярните изрази идват в модул „Текст и файлове“.
  • Два интервала един до друг дават празна част "" между тях. split(" +") (един или повече интервала) решава това.
  • Обратното на split е String.join(", ", items): долепва частите с разделител.

Пробвай

== или equals?

В първата карта промо кодът се сравняваше с equals. Защо не с ==, както числата? Въведено е admin:

Какво ще отпечата програмата?

Scanner in = new Scanner(System.in);
String user = in.nextLine();
System.out.println(user == "admin");
System.out.println(user.equals("admin"));
Отговор

Правилото: текст в Java се сравнява винаги с equals. Ако главните и малките букви нямат значение, ползвай equalsIgnoreCase.

По-точно, за любопитните

Понякога == „работи“: "admin" == "admin" е true, защото Java пази еднаквите текстове от кода в един обект. Затова грешката минава в проба с текст от кода и излиза едва с истински вход. Не разчитай на това.

Упражнение

Имена и думи

Реши задачите в редактора си. Текстът се чете от клавиатурата като цял ред.

1. Името наобратно. Прочети име и го отпечатай отзад напред. Минаваш през индексите от последния към 0 и долепваш символите в нов текст.

Вход
Мария
Изход
яираМ

2. Брой думи. Прочети изречение и преброй думите. Между думите може да има повече от един интервал, а в началото и в края може да има интервали. Подсказка: дума започва там, където символът не е интервал, а предният е интервал (или няма преден).

Вход
Днес е хубав ден
Изход
Думи: 4

3. Палиндром. Палиндромът се чете еднакво отпред назад и отзад напред. Интервалите и главните букви не се броят. Махни интервалите, направи буквите малки и сравни първия символ с последния, втория с предпоследния и т.н.

Вход
Аз обичам мач и боза
Изход
Палиндром е
Вход
Кафе с мляко
Изход
Не е палиндром

Упражнение

Проверки и броене

4. Сигурна парола. Питай за парола, докато не въведат сигурна: поне 8 знака, поне една цифра, една главна и една малка буква. След всяка слаба парола кажи какво се иска. Подсказка: do-while и проверка на всеки символ с Character.isDigit, Character.isUpperCase, Character.isLowerCase.

Вход
kafe
kafe2026
Kafe2026
Изход
Парола:
Слаба парола: поне 8 знака, цифра, главна и малка буква.
Парола:
Слаба парола: поне 8 знака, цифра, главна и малка буква.
Парола:
Паролата е приета.

Още задачи

  • Запетаи вместо интервали. Прочети изречение и замени всеки интервал със запетая. Утре заминаваме за Варна → Утре,заминаваме,за,Варна.
  • Най-дългото име. Прочети имена, разделени със запетая, и отпечатай най-дългото. Ана,Кристина,Петър → Кристина.
  • Гласните със звездичка. Замени всяка гласна (а, ъ, о, у, е, и) със *, независимо дали е главна или малка. Обичам кафе → *б*ч*м к*ф*.
  • Честота на буквите. Преброй колко пъти се среща всяка буква в текста, без значение главна или малка. Подсказка: масив с 32 брояча, по един за всеки символ от 'а' до 'я' (в таблицата със символите между тях има и две руски букви, ы и э, техните броячи просто остават 0). Индексът на буквата c е c - 'а'. Отпечатай само буквите, които се срещат.
  • Графика на символите. Като горната задача, но вместо числото отпечатай толкова звездички: а: ****.
  • Колко пъти всяка дума. Прочети изречение и за всяка различна дума отпечатай колко пъти се среща. Подсказка: раздели на думи и за всяка дума провери дали вече не е броена по-рано в масива.
  • Сортиране по дължина. Прочети думи, разделени с интервал, и ги отпечатай от най-късата към най-дългата. Сортирай масива както сортираше числа, но сравнявай дължините.
  • Брой изречения. Преброй изреченията в текст: всяко свършва с ., ! или ?. Внимавай с ... и ?!: те завършват едно изречение, не три.
  • Балансирани скоби. Провери дали скобите в текста са балансирани. С един вид скоби стига брояч: ( добавя 1, ) вади 1. Броячът не бива да пада под 0 и накрая трябва да е 0. С три вида, (), [], {}, ти трябва масив от символи, в който пазиш отворените скоби, и брояч докъде е пълен: при затваряща скоба последната отворена трябва да е от същия вид. {[()]} е балансиран, ([)] не е.

Тест

Провери се

1. Какво дава "Кафе".length()?
2. Какво прави редът name.toUpperCase(); сам, без присвояване?
3. Как се сравняват два текста в Java по съдържание?
4. Каква е разликата между 'а' и "а"?
5. Какво дава "Пн,Ср,Пт".split(",")?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·