From f0a943d7a7ffe2f363243c60ffeff796b28065e5 Mon Sep 17 00:00:00 2001 From: Nikolay Gagarinov Date: Fri, 29 May 2026 19:19:07 +0500 Subject: [PATCH] feat(31-advanced-strings): port full theory from Python and adapt to JS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Расширена теория всех 4 уроков модуля «Продвинутые строки» до объёма Python-оригинала с адаптацией под JavaScript: интерполяция через шаблонные литералы, индексация и метод at() вместо отрицательных индексов Python, метод slice() вместо срез-синтаксиса (с заменой шага/разворота на JS-идиомы), многострочные строки через бэктики. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../25-interpolation/ru/README.md | 71 ++++++++--- .../30-symbols/ru/README.md | 90 +++++++++++--- .../70-slices/ru/README.md | 116 +++++++++++++++--- .../90-multiline-strings/ru/README.md | 109 ++++++++++++---- 4 files changed, 310 insertions(+), 76 deletions(-) diff --git a/modules/31-advanced-strings/25-interpolation/ru/README.md b/modules/31-advanced-strings/25-interpolation/ru/README.md index 5041c503..a007cb27 100644 --- a/modules/31-advanced-strings/25-interpolation/ru/README.md +++ b/modules/31-advanced-strings/25-interpolation/ru/README.md @@ -1,32 +1,50 @@ -Конкатенация строк через `+` работает, но читать такой код неудобно: +Вспомним, как работает конкатенация. Для этого мы соединяем нужные строки (или переменные со строками внутри) с помощью знака `+`: ```javascript -const greeting = 'Здравствуйте'; -const firstName = 'Анна'; +const firstName = 'Joffrey'; +const greeting = 'Hello'; console.log(greeting + ', ' + firstName + '!'); -// => Здравствуйте, Анна! +// => Hello, Joffrey! ``` -Чем длиннее строка, тем сложнее уследить за кавычками и плюсами. +Но в сложных выражениях становится трудно сразу увидеть, какой текст получится на выходе. Особенно если в строке используются пробелы, запятые или кавычки: они начинают мешать восприятию. Даже текущий пример требует небольшого напряжения, чтобы понять, какой получится результат. -## Интерполяция - -Вместо конкатенации можно использовать **шаблонные строки** (template literals). Они записываются в обратных кавычках `` ` ``, а переменные вставляются с помощью `${}`: +По этой причине во многих языках существует операция, которая называется интерполяцией. Интерполяция представляет собой способ встраивать значения переменных прямо внутрь строки. В JavaScript для этого используют **шаблонные строки** (template literals). Они записываются в обратных кавычках `` ` ``, а переменные вставляются с помощью `${}`: ```javascript -const greeting = 'Здравствуйте'; -const firstName = 'Анна'; +const firstName = 'Joffrey'; +const greeting = 'Hello'; + +console.log(`${greeting}, ${firstName}!`); +// => Hello, Joffrey! +``` + +Обратные кавычки указывают, что внутри строки можно использовать переменные. Их имена записываются в `${}`, и JavaScript автоматически подставляет нужные значения. + +```text +firstName = 'Joff' +greeting = 'Hello' +`${greeting}, ${firstName}!` + └───┬───┘ └────┬────┘ + 'Hello' 'Joff' + └──────┬────────┘ + 'Hello, Joff!' +``` + +Сравните эти два примера рядом: + +```javascript +console.log(greeting + ', ' + firstName + '!'); console.log(`${greeting}, ${firstName}!`); -// => Здравствуйте, Анна! ``` -Результат тот же, но код читается гораздо проще. +Второй вариант проще и понятнее. ## Как это работает -Всё, что находится внутри `${}`, вычисляется как JavaScript-выражение, а результат вставляется в строку. +Всё, что находится внутри `${}`, вычисляется как JavaScript-выражение, а результат вставляется в строку. Поэтому внутри можно использовать не только переменные, но и любые выражения: арифметику, вызовы функций и так далее. ```javascript const price = 100; @@ -36,13 +54,30 @@ console.log(`Итого: ${price * count} рублей`); // => Итого: 300 рублей ``` -Внутри `${}` можно использовать не только переменные, но и любые выражения: арифметику, вызовы функций, условия. - ## Обратные кавычки — ключ -Шаблонная строка **обязательно** записывается в обратных кавычках `` ` ``. Одинарные или двойные кавычки не работают: +Шаблонная строка **обязательно** записывается в обратных кавычках `` ` ``. Одинарные или двойные кавычки для интерполяции не работают: + +```javascript +console.log('${firstName}'); // выведет буквально: ${firstName} +console.log(`${firstName}`); // выведет значение переменной +``` + +## Пример ```javascript -console.log('${firstName}'); // выведет буквально: ${firstName} -console.log(`${firstName}`); // выведет значение переменной +const school = 'Hexlet'; + +const whatIsIt = `${school} - online courses`; +console.log(whatIsIt); // => Hexlet - online courses ``` + +Такая запись легко читается: пробелы, дефисы и символы видны сразу. Строка выглядит именно так, как она появится в выводе. Это делает код понятным и удобным в поддержке. + +## Почему это важно + +Интерполяция предпочтительнее конкатенации почти во всех современных языках программирования. Она: + +- упрощает структуру строк; +- улучшает читаемость кода; +- снижает количество ошибок при работе с пробелами и знаками препинания. diff --git a/modules/31-advanced-strings/30-symbols/ru/README.md b/modules/31-advanced-strings/30-symbols/ru/README.md index f060ccb6..ebb5b813 100644 --- a/modules/31-advanced-strings/30-symbols/ru/README.md +++ b/modules/31-advanced-strings/30-symbols/ru/README.md @@ -1,38 +1,92 @@ -Строка в JavaScript — это последовательность символов. К каждому символу можно обратиться по его **индексу** — порядковому номеру, начиная с нуля. +Иногда нужно получить один символ из строки. Например, если сайт знает имя и фамилию пользователя и нужно вывести их в сокращённом формате вида `A. Ivanov`. Для этого потребуется взять первую букву имени. + +В JavaScript для доступа к символам строки используют индексацию. Индексация означает, что у каждого символа в строке есть свой номер, то есть индекс. Индексация начинается с нуля: у первого символа индекс `0`, у второго `1` и так далее. Представим, что у нас есть строка: + +```javascript +const firstName = 'Alexander'; +``` + +Чтобы получить первую букву, указываем её позицию (индекс) в квадратных скобках: + +```javascript +console.log(firstName[0]); // => A +``` + +Индексы в JavaScript (и во многих языках) начинаются с нуля: + +```text +Символ A l e x a n d e r +Индекс 0 1 2 3 4 5 6 7 8 +``` + +Длина строки `Alexander` равна `9`, поэтому индекс последнего символа равен `8`, то есть `9 - 1`. Длину строки можно узнать через свойство `length`: ```javascript -const language = 'JavaScript'; +console.log(firstName.length); // => 9 +console.log(firstName[firstName.length - 1]); // => r +``` + +Если изменится длина строки, то последний символ тоже сдвинется, и придётся снова вычислять его индекс. -console.log(language[0]); // => J -console.log(language[4]); // => S -console.log(language[9]); // => t +## Выход за границы строки + +В отличие от некоторых языков, в JavaScript обращение к несуществующему индексу не вызывает ошибку — возвращается специальное значение `undefined`: + +```javascript +console.log(firstName[9]); // => undefined ``` -Первый символ имеет индекс `0`, второй — `1`, и так далее. +Поэтому в программировании принято проверять длину строки и обращаться к её символам, только если это безопасно. Мы дойдём до этого в будущих уроках. -## Отрицательные индексы +## Извлечение символов с конца -В JavaScript нет отрицательных индексов (в отличие от Python). Чтобы получить последний символ, нужно вычислить индекс явно: +В некоторых языках (например, в Python) для доступа к символам с конца используют отрицательные индексы. В JavaScript квадратные скобки отрицательные индексы **не** понимают — `firstName[-1]` вернёт `undefined`. Зато есть метод `at()`, который их поддерживает: ```javascript -const word = 'hello'; -console.log(word[word.length - 1]); // => o +const word = 'Hexlet'; + +console.log(word.at(-1)); // => t, последний символ +console.log(word.at(-2)); // => e, предпоследний символ ``` -## Что происходит при выходе за границы +```text +Строка: 'H' 'e' 'x' 'l' 'e' 't' +Индекс: 0 1 2 3 4 5 +С конца: -6 -5 -4 -3 -2 -1 +``` + +Метод `at()` работает так: + +- `at(-1)` соответствует последнему символу; +- `at(-2)` соответствует предпоследнему; +- и так далее. -Если индекс больше или равен длине строки, вернётся `undefined`: +Это удобно и безопасно, потому что работает правильно даже если строка меняет свою длину. + +Индекс можно хранить в переменной: ```javascript -console.log('hi'[10]); // => undefined +const index = 0; +console.log(word[index]); // => H ``` -## Управляющие символы тоже считаются +Такой подход полезен, когда индекс вычисляется где-то в коде, а потом используется для доступа к нужному символу. + +## Спецсимволы + +При индексации учитываются обычные буквы, знаки и спецсимволы. Все они занимают позицию в строке и имеют свой индекс, даже если их «не видно» на экране. + +Например, в строке `'\nyou'` первый символ представляет собой `\n` (перенос строки), а под индексом `1` уже идёт буква `y`. Поэтому обращение `magic[1]` вернёт именно `y`. -Символ `\n` (перевод строки) — это один символ, даже если в коде он выглядит как два. +## Подумайте: что выведет этот код? ```javascript -const text = 'Na\nharis'; -// N=0, a=1, \n=2, h=3, a=4, r=5, i=6, s=7 -console.log(text[7]); // => s +const magic = '\nyou'; +console.log(magic[1]); // => ? +``` + +Вывод будет: + +```text +y ``` diff --git a/modules/31-advanced-strings/70-slices/ru/README.md b/modules/31-advanced-strings/70-slices/ru/README.md index 5376f196..50190552 100644 --- a/modules/31-advanced-strings/70-slices/ru/README.md +++ b/modules/31-advanced-strings/70-slices/ru/README.md @@ -1,40 +1,118 @@ -Когда нужно извлечь часть строки, используют метод `slice()`. +Работая со строками, мы часто сталкиваемся с задачей: извлечь часть строки. Например, получить год из даты, имя из полного ФИО или первые несколько символов из адреса электронной почты. Для таких случаев в JavaScript есть удобный инструмент — метод `slice()`. -```javascript -const text = 'Hello, World!'; +## Что такое подстрока? + +Подстрока является частью строки — тем, что входит внутрь другой строки. Например, в строке `'12-08-2034'` подстрокой может быть `'2034'`, `'12'` или даже `'-'`. Всё зависит от того, какую информацию нам нужно извлечь. + +Допустим, у нас есть строка с датой `'12-08-2034'`. Мы хотим получить из неё только год `'2034'`. В этой строке каждый символ имеет индекс (позицию), начиная с нуля: + +```text +'1' '2' '-' '0' '8' '-' '2' '0' '3' '4' + 0 1 2 3 4 5 6 7 8 9 +``` + +Год начинается с индекса 6 и заканчивается на 9. Чтобы извлечь его, мы используем `slice()`: -console.log(text.slice(7)); // => World! (с индекса 7 до конца) -console.log(text.slice(7, 12)); // => World (с 7 по 12, не включая 12) -console.log(text.slice(0, 5)); // => Hello +```javascript +const value = '12-08-2034'; +const year = value.slice(6, 10); +console.log(year); // => 2034 ``` -## Синтаксис +Вызов `value.slice(6, 10)` берёт символы с индекса 6 по 9 включительно. Формат: ```text -str.slice(start) — от start до конца -str.slice(start, end) — от start до end (end не включается) +строка.slice(начало, конец) +``` + +Символ с индексом, указанным как «конец», не включается. Его можно воспринимать как порядковый номер символа, перед которым нужно остановиться. + +```javascript +const value = 'code-basics'; + +console.log(value.slice(5, 11)); // => basics (с 5 по 10 индекс) +console.log(value.slice(0, 7)); // => code-ba (с 0 по 6 индекс) +console.log(value.slice(2, 6)); // => de-b +``` + +## Срез возвращает строку + +`slice()` всегда возвращает строку, даже если в ней только цифры. Это значит, что результат можно использовать как обычную строку: конкатенировать, выводить, передавать в функции и снова резать: + +```javascript +const value = '01-12-9873'; + +const part = value.slice(3, 7); // => 12-9 +console.log(part.slice(0, 2)); // => 12 ``` -Индексация начинается с нуля — как при обращении к символам. +Сначала мы получили подстроку `'12-9'`, а потом сделали из неё новый срез `'12'`. + +## Срез до конца или с начала + +Если второй аргумент не указать, `slice()` вернёт всё от стартового индекса до конца строки. А `slice(0)` или `slice()` без аргументов вернёт строку целиком: + +```javascript +const value = 'Hexlet'; + +console.log(value.slice(3)); // => let // с 3 символа до конца +console.log(value.slice(0, 3)); // => Hex // от начала до 3 символа +console.log(value.slice()); // => Hexlet // вся строка +``` ## Отрицательные индексы -`slice()` поддерживает отрицательные индексы: `-1` — последний символ, `-2` — предпоследний и так далее. +`slice()` умеет считать и с конца строки. Для этого используются отрицательные индексы: `-1` соответствует последнему символу, `-2` — предпоследнему и так далее. Это удобно, когда заранее неизвестна длина строки, но нужно взять «хвост» или «середину» относительно конца: ```javascript -const word = 'JavaScript'; +const value = 'Hexlet'; -console.log(word.slice(-6)); // => Script -console.log(word.slice(-6, -3)); // => Scr +console.log(value.slice(-1)); // => t // последний символ +console.log(value.slice(3, -1)); // => le // от 3 до предпоследнего +console.log(value.slice(-3)); // => let // последние три символа ``` -## Практический пример +## Срез с переменными -Убрать протокол из URL: +Границы среза не обязаны быть жёстко зафиксированы числами. Можно использовать переменные: ```javascript -const url = 'https://hexlet.io'; -console.log(url.slice(8)); // => hexlet.io +const start = 1; +const end = 5; + +const value = 'Hexlet'; +console.log(value.slice(start, end)); // => exle +``` + +Это особенно полезно, когда границы вычисляются во время работы программы. + +## Чего нет у slice() + +В некоторых языках (например, в Python) у среза есть третий параметр — шаг, и им можно, например, взять каждый второй символ или развернуть строку. У метода `slice()` шага нет. Поэтому такие задачи в JavaScript решают иначе: + +- развернуть строку можно так: + + ```javascript + const value = 'Hexlet'; + console.log(value.split('').reverse().join('')); // => telxeH + ``` + +- взять каждый второй символ — с помощью цикла (к циклам мы вернёмся позже). + +Существует и похожий метод `substring()`. Он работает почти как `slice()`, но не понимает отрицательные индексы (трактует их как `0`), поэтому для извлечения «хвоста» строки удобнее `slice()`. + +## Быстрая шпаргалка + +```javascript +const value = 'Hexlet'; + +value.slice(); // Hexlet — вся строка +value.slice(0); // Hexlet +value.slice(5); // t +value.slice(0, 5); // Hexle +value.slice(-1); // t — последний символ +value.slice(-3); // let — последние три символа +value.slice(2, -1); // xle — с третьего до предпоследнего ``` -`'https://'` занимает 8 символов, поэтому `slice(8)` возвращает всё, начиная с 9-го символа. +Не переживайте, если сейчас не запомните все комбинации: вы быстро начнёте использовать их на практике. Главное — понимать базовую структуру `строка.slice(начало, конец)`. diff --git a/modules/31-advanced-strings/90-multiline-strings/ru/README.md b/modules/31-advanced-strings/90-multiline-strings/ru/README.md index ad562ea0..ac1fdbf6 100644 --- a/modules/31-advanced-strings/90-multiline-strings/ru/README.md +++ b/modules/31-advanced-strings/90-multiline-strings/ru/README.md @@ -1,48 +1,115 @@ -Для многострочного текста обычно используют `\n`: +Иногда текст в программе должен состоять из нескольких строк. Например, при генерации письма, создании шаблона, форматировании сообщения об ошибке или просто работе с длинными текстами. + +Конечно, можно использовать символ перевода строки `\n`, как мы делали раньше: + +```javascript +const text = 'Пример текста,\nсостоящего из\nнескольких строк'; +``` + +На печати строка будет выглядеть так: + +```text +Пример текста, +состоящего из +нескольких строк +``` + +Но такой способ становится неудобным, особенно если строка длинная или нужно часто добавлять новые переносы. Каждый `\n` приходится вставлять вручную, и это ухудшает читаемость кода. + +## Многострочные строки как альтернатива + +В JavaScript есть более удобный способ записывать текст в несколько строк — шаблонные строки (template literals). Они записываются в обратных кавычках `` ` ``, и все переносы строк внутри сохраняются буквально: ```javascript -console.log('Строка 1\nСтрока 2\nСтрока 3'); +const text = `Пример текста, +состоящего из +нескольких строк`; ``` -Но при большом количестве строк это неудобно. +Теперь в коде всё выглядит так же, как и при выводе: -## Шаблонные строки для многострочного текста +```text +Пример текста, +состоящего из +нескольких строк +``` -Шаблонные строки (в обратных кавычках) сохраняют все переносы строк буквально: +Каждый перенос в исходном коде превращается в символ `\n` внутри строки. + +## Осторожно с пустой строкой в конце + +Где вы поставите закрывающую обратную кавычку — там и закончится текст. Если перенести её на новую строку, этот перенос тоже войдёт в результат: ```javascript -const text = `Первая строка -Вторая строка -Третья строка`; +const text = `Пример текста, +состоящего из +нескольких строк +`; +console.log('===='); console.log(text); -// Первая строка -// Вторая строка -// Третья строка +console.log('===='); ``` -Перенос в исходном коде становится `\n` в строке. +Вывод: + +```text +==== +Пример текста, +состоящего из +нескольких строк -## Пример: email-письмо +==== +``` + +Обратите внимание: появляется пустая строка в конце. Чтобы её избежать, не переносите закрывающую кавычку на новую строку: ```javascript -const email = `Уважаемый клиент! +const text = `Пример текста, +состоящего из +нескольких строк`; +``` + +## Преимущества многострочных строк -Ваш заказ принят. -Спасибо за покупку!`; +- Читаемость кода: текст в коде выглядит почти как на экране. +- Удобство при редактировании: легко добавлять, удалять и менять строки. +- Не нужно экранировать кавычки внутри: + +```javascript +const quote = `Здесь не нужно экранировать 'одинарные' и "двойные" кавычки`; ``` -Это удобнее, чем: +## Интерполяция внутри многострочной строки + +Шаблонные строки совмещают многострочность и интерполяцию, поэтому внутри можно подставлять значения переменных через `${}`: ```javascript -const email = 'Уважаемый клиент!\n\nВаш заказ принят.\nСпасибо за покупку!'; +const a = 'A'; +const b = 'B'; + +const text = `${a} и ${b} +сидели на трубе`; +``` + +Вывод: + +```text +A и B +сидели на трубе ``` -## Важно +Это особенно удобно для шаблонов, писем, сообщений об ошибках и многострочных описаний. -Отступы в коде войдут в строку. Если сделать отступ внутри шаблонной строки, он появится в тексте. +## Осторожно с отступами + +Отступы в коде войдут в строку. Если сделать отступ внутри шаблонной строки, он появится в тексте: ```javascript const message = `Hello - World`; // строка содержит 2 пробела перед World + World`; // строка содержит 2 пробела перед World ``` + +## Компьютер и человек воспринимают код по-разному + +JavaScript одинаково обработает и строку с `\n`, и многострочную строку — для движка это одно и то же. Но для человека, читающего код, многострочные строки намного удобнее и нагляднее.