Подсчёт символов в строке: длина, пробелы, байты
Подсчёт символов в строке кажется элементарной задачей: вызвал длину и готово. Но как только в тексте появляются пробелы, переводы строк, кириллица или эмодзи, разные способы счёта начинают давать разные числа, и студент получает «неправильный» ответ в задаче, хотя код вроде бы верный. В этой статье разберём, что именно считается символом, чем длина с пробелами отличается от длины без них, почему один эмодзи может прибавлять к длине сразу две единицы и как одна и та же строка занимает разное число байтов. Чтобы сразу увидеть все эти числа на своём тексте, вставьте строку в калькулятор ниже: он покажет длину разными способами, разбивку по категориям знаков и размер в байтах.
Что такое символ и длина строки
Строка для компьютера - это последовательность символов, и длина строки это просто число элементов в этой последовательности. В большинстве языков «посчитать символы» означает вызвать встроенную функцию длины: в Python, в JavaScript, в Java. Для простого текста из латиницы все эти способы дают одинаковый и ожидаемый результат: в строке «Hello» ровно 5 символов.
Сложности начинаются, когда нужно уточнить, что именно мы считаем. Считать ли пробелы? А переводы строк и табуляции? Является ли эмодзи одним символом или несколькими? От ответа зависит итоговое число, и в учебных задачах формулировка обычно требует конкретного варианта - например, «сколько значимых символов без учёта пробелов».
Подсчёт символов с пробелами и без них
Самый частый вопрос в задачах: посчитать символы с пробелами и без них. Полная длина строки включает абсолютно все знаки, в том числе пробелы между словами:
Длина без пробелов получается, если убрать из строки символы пробела и измерить остаток:
Разница между этими числами равна количеству пробелов в тексте. Важно различать обычный пробел (символ ) и другие пробельные знаки: табуляцию, перевод строки, неразрывный пробел. В строгом подсчёте «без пробельных» убирают все из них, поэтому такое число может быть меньше, чем просто «без пробелов».

На практике это даёт три разных ответа на один и тот же вопрос «сколько символов». Когда условие задачи говорит «без пробелов», почти всегда имеется в виду удаление именно обычных пробелов, но если в тексте есть табуляции, стоит уточнить, считать ли их.
Категории символов: буквы, цифры, знаки
Часто требуется не просто общая длина, а разбивка: сколько в строке букв, сколько цифр, сколько знаков пунктуации. Каждый символ попадает ровно в одну категорию, и сумма по всем категориям равна полному числу символов строки:
Буквами считаются символы из категории Unicode «letter» - сюда входят и кириллица, и латиница, и буквы других алфавитов. Цифры это десятичные цифры, пунктуация и символы вроде скобок, точек, знаков операций объединяются в отдельную группу. Такая разбивка полезна для проверки паролей, валидации ввода и анализа текста. В калькуляторе выше эта разбивка строится как столбчатая диаграмма, чтобы сразу было видно, из чего состоит строка.
Отдельно стоит задача подсчёта частоты символов: сколько раз каждый знак встречается в строке. Здесь результат это уже не одно число, а таблица «символ - количество». Алгоритм простой: проходим по строке посимвольно и для каждого знака увеличиваем его счётчик в словаре. Сумма всех значений в таком словаре снова равна длине строки, что удобно использовать как проверку: если сумма частот не совпала с длиной, в подсчёте есть ошибка. Частота символов лежит в основе многих задач - от поиска самого частого знака до построения частотного словаря для сжатия текста.
При подсчёте по категориям важно решить судьбу регистра. Если задача требует считать «количество букв» без учёта регистра, то и заглавные, и строчные попадают в одну категорию букв - это происходит само собой. Но если нужна частота конкретных букв, то заглавная и строчная это разные символы с разными код-поинтами, и без предварительного приведения к нижнему регистру они посчитаются раздельно.
Подсчёт символов в Python и JavaScript
В Python длина строки считается функцией :
s = "Привет, мир!"
print(len(s)) # 12 - все символы, включая пробел и запятую
print(len(s.replace(" ", ""))) # 11 - без пробелов
Функция в Python считает код-поинты Unicode, поэтому каждая кириллическая буква это один символ, и для обычного текста результат совпадает с человеческой интуицией.
В JavaScript свойство устроено иначе: оно возвращает число единиц UTF-16, а не число символов. Для латиницы и кириллицы это одно и то же, но эмодзи и редкие символы кодируются суррогатной парой и занимают две единицы. Поэтому строка с одним эмодзи может иметь на единицу больше, чем реальное число символов. Чтобы посчитать настоящие символы, используют спред-оператор:
const s = "AB🙂"; console.log(s.length); // 4 - UTF-16 единицы console.log([...s].length); // 3 - реальные код-поинты
Размер строки в байтах UTF-8
Число символов и размер строки в памяти это разные величины. В кодировке UTF-8 один символ занимает от одного до четырёх байтов: латинская буква и цифра кодируются одним байтом, кириллица обычно двумя, многие символы тремя, а эмодзи четырьмя. Поэтому байтовая длина строки почти всегда больше числа символов, если в тексте есть не-латинские знаки:
Эта разница важна, когда есть ограничение «не более N байтов» (например, в базах данных или сетевых протоколах): строка из 100 кириллических символов займёт около 200 байтов, и проверка по числу символов вместо байтов пропустит слишком длинное значение. Калькулятор показывает байтовую длину рядом с числом символов, чтобы расхождение было наглядным.
Чтобы посчитать байты явно, строку кодируют в нужную кодировку и измеряют длину результата. В Python это , в JavaScript подойдёт . Полезно держать в голове ориентир: латиница и цифры - по одному байту, кириллица - по два, а эмодзи - по четыре. Тогда расхождение между числом символов и числом байтов перестаёт удивлять и становится предсказуемым: оно ровно равно сумме «лишних» байтов всех многобайтовых символов.
Частые ошибки
- Путаница длины с пробелами и без них. Если в задаче сказано «без пробелов», нельзя сдавать результат напрямую - нужно сначала удалить пробелы. Разница равна числу пробелов.
- Счёт байтов вместо символов. В языках, где строка хранится в UTF-8, наивный счёт байтов даёт для кириллицы число вдвое больше реального. Считайте символы, а не байты, если нужно именно число знаков.
- Эмодзи как два символа. В JavaScript считает единицы UTF-16, поэтому эмодзи даёт +2. Для реального числа символов используйте код-поинты ().
- Забытые невидимые символы. Перевод строки, табуляция и неразрывный пробел тоже считаются символами. Лишний перевод строки в конце часто даёт длину на единицу больше ожидаемой.
- Двойной счёт при разбивке по категориям. Каждый символ относится ровно к одной категории; если суммы по категориям не сходятся с общей длиной, где-то символ посчитан дважды или пропущен.
FAQ
Как посчитать количество символов в строке без пробелов? Удалите из строки пробелы и измерьте длину остатка: в Python это , в JavaScript . Разница с полной длиной равна числу пробелов в тексте.
Почему len строки с эмодзи больше, чем число видимых символов? В JavaScript считает единицы кодировки UTF-16, а эмодзи кодируется суррогатной парой из двух таких единиц. Чтобы получить настоящее число символов, считайте код-поинты через . В Python считает код-поинты сразу, поэтому такой проблемы нет.
Чем число символов отличается от размера строки в байтах? Число символов это сколько знаков в строке, а размер в байтах это сколько памяти они занимают. В UTF-8 один символ занимает от одного до четырёх байтов, поэтому строка с кириллицей в байтах примерно вдвое длиннее, чем в символах.
Коротко
Подсчёт символов в строке зависит от того, что именно считать: полная длина включает пробелы и переводы строк, длина без пробелов меньше на их число, а сумма по категориям знаков равна общему числу символов. В Python считает код-поинты Unicode, а в JavaScript считает единицы UTF-16, из-за чего эмодзи даёт лишнюю единицу - для реального счёта берут . Размер строки в байтах UTF-8 это отдельная величина: один символ занимает от одного до четырёх байтов, поэтому байтовая длина почти всегда больше числа символов.
Читайте также

230 пространственных групп симметрии: откуда берётся число
230 пространственных групп симметрии в кристаллографии: как из 32 точечных групп, 14 решёток Браве и трансляций получается ровно 230 групп Фёдорова, и зачем это нужно.

Декогеренция квантовой системы: как теряется суперпозиция
Декогеренция квантовой системы простыми словами: почему суперпозиция разрушается при взаимодействии со средой, как считать время декогеренции и чем она отличается от коллапса волновой функции.

Эффект Мейснера-Оксенфельда: вытеснение поля
Эффект Мейснера-Оксенфельда: как сверхпроводник выталкивает магнитное поле при переходе ниже критической температуры, чем он отличается от идеального проводника и при чём здесь глубина Лондона.