Работа с текст
Проблем
Кодът е верен, а не минава
Магазинът дава 10% отстъпка с код SUMMER10. Клиентът го преписва от рекламата, но пише с малки букви и случайно слага интервал отпред:
const code = await ask("");if (code === "SUMMER10") { console.log("Отстъпка 10%");} else { console.log("Невалиден код");}rl.close(); summer10Невалиден кодЗа човек кодът е същият. За програмата summer10 и SUMMER10 са различни текстове: първият има един символ повече, а буквите са други. Трябва да можеш да гледаш вътре в текста и да го оправяш.
Идеята
Текстът е поредица от символи
Текстът е подредени един след друг символи: букви, цифри, интервали, знаци. Всеки символ има индекс, като в масив. Първият е с индекс 0.
const code = "SUMMER10";console.log(code.length);console.log(code[0]);console.log(code[code.length - 1]);8S0code.lengthе броят на символите.code[0]е символът с индекс 0. Последният символ е с индексlength - 1.
Отделен тип за един символ (в Java и C# се казва char) тук няма. Символът е просто текст с дължина 1. Единичните и двойните кавички правят едно и също: 'S' и "S" са еднакви текстове.
const code = "SUMMER10";console.log(code.at(-1));console.log(code[-1]);console.log(typeof code[0]);console.log(code[0].length);console.log('S' === "S");0undefinedstring1truecode.at(-1) е последният символ: отрицателният индекс брои отзад. С квадратни скоби това не става: code[-1] дава undefined.
И при текста, и при масива дължината е length, без скоби.
Виж го
Символ по символ
Колко цифри има в телефонния номер? Минаваш с цикъл през индексите от 0 до последния и гледаш всеки символ:
const phone = "0888 123 456";let digits = 0;for (let i = 0; i < phone.length; i++) { const c = phone[i]; if (c >= "0" && c <= "9") { digits++; }}console.log("Цифри: " + digits);Цифри: 10c >= "0" && c <= "9" работи, защото всеки символ има код: число в таблицата със символите. Текстовете се сравняват по кодовете на символите. Цифрите от "0" до "9" имат поредни кодове, буквите от "a" до "z" също.
По-точно, за любопитните
- Готови методи като „цифра ли е“ няма. За цифра сравняваш, както горе. За буква: символът е главна буква, ако
c !== c.toLowerCase()(малката му форма е друга), и малка, акоc !== c.toUpperCase(). Това знае и кирилицата. - Кодът на символ дава
"A".charCodeAt(0), тоест 65. Обратно,String.fromCharCode(66)е"B". Внимавай:"a" + 1не е грешка, а текстът"a1". - Без индекс:
for (const c of phone)минава направо през символите на текста.
const c = "Ж";console.log(c >= "0" && c <= "9");console.log(c.toUpperCase() !== c.toLowerCase());console.log(c !== c.toLowerCase());console.log("ж" !== "ж".toUpperCase());console.log("A".charCodeAt(0), String.fromCharCode(66));console.log("a" + 1);let digits = 0;for (const ch of "0888 123 456") { if (ch >= "0" && ch <= "9") { digits++; }}console.log(digits);falsetruetruetrue65 Ba110Пробвай
Кой символ?
Какво ще отпечата програмата?
const word = "Поръчка";console.log(word[3]);console.log(word.length);Индексите са П 0, о 1, р 2, ъ 3. Символът с индекс 3 е четвъртият: „ъ“. Дължината е броят на всички символи, 7. Последният индекс е 6.
Идеята
Методите на текста
Текстът идва с готови методи: действия, които викаш с точка след текста. Ето поправката на промо кода:
const code = " summer10";const clean = code.trim().toUpperCase();console.log("[" + clean + "]");console.log(clean === "SUMMER10");[SUMMER10]truetrim() маха интервалите отпред и отзад. toUpperCase() прави всички букви главни. Методите се нареждат един след друг: първият връща текст и върху него се вика вторият.
Още няколко, върху имейл адрес:
const email = "ivan.petrov@mail.bg";console.log(email.includes("@"));console.log(email.indexOf("@"));console.log(email.slice(0, email.indexOf("@")));console.log(email.replaceAll(".", " "));console.log(email.endsWith(".bg"));true11ivan.petrovivan petrov@mail bgtrue| Метод | Какво прави |
|---|---|
includes(x) |
има ли го x вътре |
indexOf(x) |
на кой индекс е x за първи път (-1, ако го няма) |
slice(a, b) |
част от текста |
replaceAll(x, y) |
всяко x се заменя с y |
startsWith(x), endsWith(x) |
започва ли (свършва ли) с x |
toLowerCase() |
всички букви малки |
Внимавай с replace: в JavaScript той сменя само първото срещане. За всички пишеш replaceAll.
console.log("ivan.petrov@mail.bg".replace(".", " "));console.log("ivan.petrov@mail.bg".indexOf("#"));console.log("Кафе".startsWith("К"));console.log("Кафе".toLowerCase());ivan petrov@mail.bg-1trueкафеПо-точно, за любопитните
slice(a, b) взима символите от индекс a до индекс b, без b. Броят им е b - a. Само с един аргумент взима всичко до края. Отрицателният индекс брои отзад: slice(-2) са последните два символа.
const date = "2026-10-24";console.log(date.slice(5, 7));console.log(date.slice(8));console.log(date.slice(-2));102424Идеята
Текстът не се променя
Има една особеност, която обърква всички в началото:
let name = "мария";name.toUpperCase();console.log(name);name = name.toUpperCase();console.log(name);марияМАРИЯВторият ред не прави нищо видимо. toUpperCase() не променя name. Той прави нов текст с главни букви и го връща. Никой не го записва и той се губи.
Веднъж създаден, текстът не може да се промени. Казва се, че е неизменим (immutable). Всеки метод, който „променя“ текст, всъщност връща нов. За да го запазиш, присвояваш: name = name.toUpperCase();.
let name = "мария";name.toUpperCase();console.log(name);name = name.toUpperCase();console.log(name);Стъпка по стъпка, с думи
- В name е текстът „мария“: 5 символа с индекси от 0 до 4.
- toUpperCase() не пипа „мария“. Прави нов текст „МАРИЯ“.
- Никой не записва новия текст и той се губи.
- В name си е „мария“ и то се отпечатва.
- Пак нов текст „МАРИЯ“, но сега = го записва в name. Старото „мария“ отпада.
- Сега в name е „МАРИЯ“.
По-точно, за любопитните
- Символ вътре в текста не може да се смени и с индекс.
name[0] = "М"в обикновен скрипт мълчи: няма грешка, ноnameси остава"мария". Във файл сimport(модул) същият ред спира програмата сTypeError: Cannot assign to read only property '0' of string. Правиш нов текст, например"М" + name.slice(1). - Когато имаш много парчета, събери ги в масив и ги долепи наведнъж с
join:
const parts = ["мляко", "хляб", "яйца"];console.log(parts.join(", "));мляко, хляб, яйцаПробвай
Намери грешката
Потребителят въвежда имейла си с главни букви и интервали. Програмата трябва да го изчисти и да го пусне, но казва „Няма такъв потребител.“. На кой ред е грешката?
Избери реда с грешката.
email.trim(); връща нов текст без интервалите, но той не се записва никъде. email си остава с интервалите. Поправката е email = email.trim();, както на ред 2.
Идеята
Текстът на части
Често текстът съдържа няколко неща, разделени със знак: продукти със запетая, думи с интервал. split го разделя на части и връща масив от текстове:
const list = "мляко,хляб,яйца,сирене";const items = list.split(",");console.log("Продукти: " + items.length);for (let i = 0; i < items.length; i++) { console.log((i + 1) + ". " + items[i]);}Продукти: 41. мляко2. хляб3. яйца4. сиренеРазделителят не влиза в частите. Оттук нататък работиш с обикновен масив: дължина, индекси, цикъл.
Така се чете и цял ред числа от клавиатурата: разделяш го и превръщаш всяка част в число. Точно това ти липсваше в миналия урок за таблиците:
const parts = (await ask("")).split(" ");let sum = 0;for (const p of parts) { sum += Number(p);}console.log(sum);rl.close();42 38 51 47 60238По-точно, за любопитните
- Два интервала един до друг дават празна част
''между тях.split(/ +/)(един или повече интервала) решава това. Нещото между наклонените черти е регулярен израз, шаблон за текст. Иначеsplitполучава обикновен текст иsplit(".")разделя по точка. - Обратното на
splitеitems.join(", "): долепва частите с разделител.
console.log("а б".split(" "));console.log("а б".split(/ +/));console.log("а.б".split("."));console.log(["а", "б"].join(", "));[ 'а', '', 'б' ][ 'а', 'б' ][ 'а', 'б' ]а, бПробвай
Едно и също ли е?
В JavaScript === сравнява съдържанието на текстовете, буква по буква. Но главната и малката буква са различни символи. Въведено е София:
Какво ще отпечата програмата?
const city = await ask("");console.log(city === "София");console.log(city === "софия");console.log(city.toLowerCase() === "софия");rl.close();city === "София" е true: буквите са същите. "софия" започва с малко „с“, а то е друг символ, затова е false. Ако главните и малките букви нямат значение, сравни двата текста с малки букви: city.toLowerCase() === "софия".
По-точно, за любопитните
Има и == с две равенства. Той първо превръща двете страни в един тип и чак тогава сравнява, затова текстът "1" и числото 1 излизат равни:
console.log("1" == 1);console.log("1" === 1);truefalseСравнявай винаги с ===.
Упражнение
Имена и думи
Реши задачите в редактора си. Текстът се чете от клавиатурата като цял ред.
1. Името наобратно. Прочети име и го отпечатай отзад напред. Минаваш през индексите от последния към 0 и долепваш символите в нов текст.
МарияяираМ2. Брой думи. Прочети изречение и преброй думите. Между думите може да има повече от един интервал, а в началото и в края може да има интервали. Подсказка: дума започва там, където символът не е интервал, а предният е интервал (или няма преден).
Днес е хубав денДуми: 43. Палиндром. Палиндромът се чете еднакво отпред назад и отзад напред. Интервалите и главните букви не се броят. Махни интервалите, направи буквите малки и сравни първия символ с последния, втория с предпоследния и т.н.
Аз обичам мач и бозаПалиндром еКафе с млякоНе е палиндромУпражнение
Проверки и броене
4. Сигурна парола. Питай за парола, докато не въведат сигурна: поне 8 знака, поне една цифра, една главна и една малка буква. След всяка слаба парола кажи какво се иска. Подсказка: do-while и проверка на всеки символ: цифра с c >= "0" && c <= "9", главна с c !== c.toLowerCase(), малка с c !== c.toUpperCase().
kafekafe2026Kafe2026Парола:Слаба парола: поне 8 знака, цифра, главна и малка буква.Парола:Слаба парола: поне 8 знака, цифра, главна и малка буква.Парола:Паролата е приета.Още задачи
- Запетаи вместо интервали. Прочети изречение и замени всеки интервал със запетая.
Утре заминаваме за Варна→Утре,заминаваме,за,Варна. - Най-дългото име. Прочети имена, разделени със запетая, и отпечатай най-дългото.
Ана,Кристина,Петър→Кристина. - Гласните със звездичка. Замени всяка гласна (а, ъ, о, у, е, и) със
*, независимо дали е главна или малка.Обичам кафе→*б*ч*м к*ф*. - Честота на буквите. Преброй колко пъти се среща всяка буква в текста, без значение главна или малка. Подсказка: масив с 32 брояча, по един за всеки символ от
'а'до'я'(в таблицата със символите между тях има и две руски букви, ы и э, техните броячи просто остават 0). Индексът на букватаcеc.charCodeAt(0) - "а".charCodeAt(0). Отпечатай само буквите, които се срещат. - Графика на символите. Като горната задача, но вместо числото отпечатай толкова звездички:
а: ****. - Колко пъти всяка дума. Прочети изречение и за всяка различна дума отпечатай колко пъти се среща. Подсказка: раздели на думи и за всяка дума провери дали вече не е броена по-рано в масива.
- Сортиране по дължина. Прочети думи, разделени с интервал, и ги отпечатай от най-късата към най-дългата. Сортирай масива както сортираше числа, но сравнявай дължините.
- Брой изречения. Преброй изреченията в текст: всяко свършва с
.,!или?. Внимавай с...и?!: те завършват едно изречение, не три. - Балансирани скоби. Провери дали скобите в текста са балансирани. С един вид скоби стига брояч:
(добавя 1,)вади 1. Броячът не бива да пада под 0 и накрая трябва да е 0. С три вида,(),[],{}, ти трябва масив от символи, в който пазиш отворените скоби, и брояч докъде е пълен: при затваряща скоба последната отворена трябва да е от същия вид.{[()]}е балансиран,([)]не е.
Тест