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

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

Проблем

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

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

string code = Console.ReadLine();
if (code == "SUMMER10")
{
Console.WriteLine("Отстъпка 10%");
}
else
{
Console.WriteLine("Невалиден код");
}
Вход
summer10
Изход
Невалиден код

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

Идеята

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

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

string code = "SUMMER10";
Console.WriteLine(code.Length);
Console.WriteLine(code[0]);
Console.WriteLine(code[code.Length - 1]);
Изход
8
S
0
  • code.Length е броят на символите.
  • code[0] е символът с индекс 0. Последният символ е с индекс Length - 1.

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

И при текста, и при масива дължината е Length, без скоби.

Виж го

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

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

string phone = "0888 123 456";
int digits = 0;
for (int i = 0; i < phone.Length; i++)
{
char c = phone[i];
if (c >= '0' && c <= '9')
{
digits++;
}
}
Console.WriteLine("Цифри: " + digits);
Изход
Цифри: 10

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

По-точно, за любопитните
  • За такива проверки има готови методи: char.IsDigit(c), char.IsLetter(c), char.IsUpper(c), char.IsLower(c). Те знаят и кирилицата.
  • Кодът на символ получаваш с превръщане: (int) 'A' е 65. Обратно, (char) 66 е 'B'. Затова 'a' + 1 е числото 98, а не буквата b.
  • Без индекс: foreach (char c in phone) минава направо през символите на текста.

Пробвай

Кой символ?

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

string word = "Поръчка";
Console.WriteLine(word[3]);
Console.WriteLine(word.Length);
Отговор

Идеята

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

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

string code = " summer10";
string clean = code.Trim().ToUpper();
Console.WriteLine("[" + clean + "]");
Console.WriteLine(clean == "SUMMER10");
Изход
[SUMMER10]
True

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

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

string email = "ivan.petrov@mail.bg";
Console.WriteLine(email.Contains("@"));
Console.WriteLine(email.IndexOf("@"));
Console.WriteLine(email.Substring(0, email.IndexOf("@")));
Console.WriteLine(email.Replace(".", " "));
Console.WriteLine(email.EndsWith(".bg"));
Изход
True
11
ivan.petrov
ivan petrov@mail bg
True
Метод Какво прави
Contains(x) има ли го x вътре
IndexOf(x) на кой индекс е x за първи път (-1, ако го няма)
Substring(a, n) част от текста
Replace(x, y) всяко x се заменя с y
StartsWith(x), EndsWith(x) започва ли (свършва ли) с x
ToLower() всички букви малки
По-точно, за любопитните

Substring(a, n) взима n символа, като започва от индекс a. Вторият аргумент е броят символи, не индекс (в Java е обратното, там е индексът на края). Само с един аргумент взима всичко до края:

string date = "2026-10-24";
Console.WriteLine(date.Substring(5, 2));
Console.WriteLine(date.Substring(8));
Изход
10
24

Идеята

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

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

string name = "мария";
name.ToUpper();
Console.WriteLine(name);
name = name.ToUpper();
Console.WriteLine(name);
Изход
мария
МАРИЯ

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

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

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

Пробвай

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

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

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

Идеята

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

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

string list = "мляко,хляб,яйца,сирене";
string[] items = list.Split(',');
Console.WriteLine("Продукти: " + items.Length);
for (int i = 0; i < items.Length; i++)
{
Console.WriteLine((i + 1) + ". " + items[i]);
}
Изход
Продукти: 4
1. мляко
2. хляб
3. яйца
4. сирене

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

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

string[] parts = Console.ReadLine().Split(' ');
int sum = 0;
foreach (string p in parts)
{
sum += int.Parse(p);
}
Console.WriteLine(sum);
Вход
42 38 51 47 60
Изход
238
По-точно, за любопитните
  • Два интервала един до друг дават празна част "" между тях. Split(' ', StringSplitOptions.RemoveEmptyEntries) пропуска празните части.
  • Разделителите може да са няколко: Split(',', ';').
  • Обратното на Split е string.Join(", ", items): долепва частите с разделител.

Пробвай

Едно и също ли е?

В C# == сравнява съдържанието на текстовете, буква по буква. Но главната и малката буква са различни символи. Въведено е София:

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

string city = Console.ReadLine();
Console.WriteLine(city == "София");
Console.WriteLine(city == "софия");
Console.WriteLine(city.ToLower() == "софия");
Отговор

Има и метод за същото: string.Equals(city, "софия", StringComparison.OrdinalIgnoreCase). В Java == за текст не сравнява буквите, а там се ползва equals. Ако някога четеш Java код, имай го предвид.

Упражнение

Имена и думи

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

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

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

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

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

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

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

Упражнение

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

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

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

Още задачи

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

Тест

Провери се

1. Какво дава "Кафе".Length?
2. Какво прави редът name.ToUpper(); сам, без присвояване?
3. Какво дава "Варна" == "варна" в C#?
4. Каква е разликата между 'а' и "а"?
5. Какво дава "Пн,Ср,Пт".Split(',')?

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