Длина строки

Считайте текст сразу пятью способами: символы так, как вы их видите, кодовые точки (len() в Python), единицы UTF-16 (.length в JavaScript), слова и строки.

Ввод
Символы
0
Кодовые точки
0
Единицы UTF-16
0
Слова
0
Строки
0

Почему у вопроса «какой длины этот текст?» больше одного ответа

Звучит как тривиальный вопрос, но длина фрагмента текста полностью зависит от того, что именно вы считаете. Человек считает символы, которые видит. База данных считает объём хранилища, который занимает значение. JavaScript считает нечто иное. Когда эти числа расходятся — а с эмодзи, буквами с диакритикой и нелатинскими письменностями это происходит часто — одна-единственная «длина» вводит в заблуждение. Этот инструмент показывает пять осмысленных мер рядом, чтобы вы выбрали ту, которая важна в вашем случае.

Пять метрик с пояснениями

  • Символы (графемы): то, что человек воспринимает как один символ. Эмодзи семьи вроде 👨‍👩‍👧 или буква с комбинирующим диакритическим знаком считаются за один — это счёт, который совпадает с подсчётом «на глаз».
  • Кодовые точки (code points): количество скалярных значений Unicode. Один видимый символ может состоять из нескольких соединённых кодовых точек, поэтому это число часто больше, чем количество графем.
  • Единицы UTF-16: значение, которое JavaScript возвращает из свойства .length строки. Символы за пределами базовой многоязычной плоскости (большинство эмодзи) занимают по две единицы UTF-16.
  • Слова: количество словоподобных токенов, определяемых с учётом Unicode, а не наивным разбиением по пробелам.
  • Строки: количество строк, с подсчётом каждого переноса строки.

Почему эмодзи и диакритика ломают наивный подсчёт

Современный текст построен на Unicode, который представляет многие видимые символы как последовательности, а не как отдельные единицы. Эмодзи флага — это два региональных символа-индикатора. Эмодзи семьи — это несколько фигур, соединённых невидимыми символами «соединитель нулевой ширины». Буква é может быть одной кодовой точкой или простой e с последующим комбинирующим знаком. Каждый из них выглядит как один символ, но может считаться за два, три или больше в зависимости от метрики. Именно поэтому ручной подсчёт или доверие одному числу приводят к ошибкам.

Какой счёт использовать?

  • Ограничения на символы, которые видят люди (биография, поле в стиле твита, предпросмотр SMS): используйте «Символы» (графемы), потому что это совпадает с тем, что считает пользователь.
  • Работа со строками в JavaScript, индексация или срезы: используйте единицы UTF-16, так как именно на них основаны .length и индексы строки.
  • Размеры столбцов базы данных: проверьте, измеряется ли ваш столбец в символах или в байтах — многие ограничены байтами, а байты UTF-8 снова отличаются от всех этих значений.
  • Подсчёт слов или строк для редакторов и читаемости: используйте метрики «Слова» и «Строки».

Что называют длиной Python и JavaScript

Два из пяти показателей выше — это ровно те, ради которых сюда чаще всего приходят, и принадлежат они разным языкам. len() в Python и .length в JavaScript оба описывают как длину строки, и на всём, что выходит за пределы простого ASCII, они отвечают по-разному для одного и того же текста в один и тот же момент. Ни один из них не ошибается: они считают разные единицы, и оба значения показаны выше, чтобы разницу можно было прочитать, а не угадывать.

  • Python: len() возвращает количество кодовых точек Unicode, потому что строка в Python 3 — это последовательность кодовых точек. Смотрите показатель «Кодовые точки»: именно это число и даст len().
  • JavaScript: .length возвращает количество единиц кода UTF-16, потому что строка JavaScript хранится в UTF-16. Смотрите показатель «Единицы UTF-16». А вот Array.from(text).length проходит строку по кодовым точкам и потому совпадает с Python.
  • Ни один из них не считает то, что вы видите. Показатель «Символы» — это количество графем, и никакая встроенная длина в этих языках его не даёт: JavaScript нужен Intl.Segmenter, а Python — сторонний пакет. Если ограничение, которое вы вводите, будет читать человек, вам нужен именно этот показатель.
  • Слова и Строки тоже не принадлежат ни одному из языков. Оба могут приблизить их разбиением по пробелам и по переносам строк, и оба расходятся с показанными здесь числами, которые учитывают Unicode, — на тексте, написанном без пробелов, на пунктуации и на переносе строки в самом конце текста.

Пример за кнопкой «Загрузить пример» — самый быстрый способ увидеть разрыв. Его эмодзи семьи для читателя один символ, для Python пять кодовых точек, а для JavaScript восемь единиц UTF-16: три из этих пяти кодовых точек лежат за пределами базовой многоязычной плоскости и стоят по две единицы, а два невидимых соединителя между ними — по одной. Значит, поле, куда человеку разрешено вписать двадцать символов, действительно вмещает двадцать на глаз, а наивная проверка, написанная на любом из двух языков, отвергает текст, который помещается.

Длина — это не размер в байтах

Ни один из пяти показателей выше не является количеством байтов, и эти две вещи легко спутать. Счёт — свойство самого текста; размер в байтах — свойство текста после того, как он записан в какой-то кодировке, поэтому одна и та же строка занимает один размер в UTF-8 и другой в UTF-16. Всё, что измеряется в байтах, приходится измерять после кодирования, и выбранная кодировка — часть ответа.

  • UTF-8 использует почти всё вокруг, и он переменной ширины: буква, цифра или знак препинания из ASCII занимает один байт, большинство букв с диакритикой и нелатинских символов — два или три, а многие эмодзи — четыре. Сто символов равны ста байтам только тогда, когда все они из ASCII: те же сто символов на греческом, иврите, арабском или китайском весят вдвое-втрое больше.
  • Python: len() считает кодовые точки, поэтому кодируйте перед измерением. len(text.encode('utf-8')) — это количество байтов UTF-8, а другая кодировка на этом месте даст другое число, в чём и состоит суть.
  • JavaScript: .length считает единицы UTF-16, так что это тоже не количество байтов. new TextEncoder().encode(text).length даёт количество байтов UTF-8 и в браузере, и в Node, а TextEncoder выдаёт только UTF-8, так что называть кодировку негде.
  • Прежде чем что-то считать, проверьте, в каких единицах записано ваше ограничение. Одни СУБД объявляют столбец в символах, другие — в байтах, значение HTTP-заголовка и размер файла — это байты, а правило, написанное для людей, — это то, что показывает поле «Символы». Всё, что измеряется в символах, уже есть выше; всё, что измеряется в байтах, требует длины после кодирования.

Когда количество байтов получено, дальше идёт Конвертер размеров данных: он переводит сырое число байтов сразу в обе системы единиц — построенную на степенях тысячи и построенную на степенях двойки — и показывает, как один и тот же размер сообщит каждая программа на вашей машине. Эта страница заканчивается там, где начинается кодирование; та начинается с числа байтов.

Частые вопросы

Какой счёт соответствует длине строки в JavaScript?
Значение единиц UTF-16 соответствует «сырому» свойству .length в JavaScript. Если ваш код режет или индексирует строки, именно это число определяет его поведение.
Почему один эмодзи считается несколькими символами?
Многие эмодзи состоят из нескольких соединённых кодовых точек Unicode. Как графема (то, что вы видите) это один символ, но его счётчики кодовых точек и UTF-16 выше, поэтому каждая мера показана отдельно.
Считает ли он завершающие пробелы и переносы строк?
Да. Считается каждый символ, который вы вставили, включая начальные и конечные пробелы и переносы строк. Если итоги кажутся больше ожидаемого, проверьте наличие невидимых конечных пробелов.
Отправляется ли мой текст на сервер?
Нет. Весь подсчёт происходит в вашем браузере. Текст, который вы вводите или вставляете, никогда не покидает ваше устройство.
Что такое графема?
Графема, или «кластер графем», — это символ в том виде, в каком его воспринимает пользователь: наименьшая единица, которую читатель назвал бы одним символом, даже если она состоит из нескольких кодовых точек.
Чем байты отличаются от этих значений?
Байты зависят от кодировки. В UTF-8 буква ASCII занимает один байт, большинство символов с диакритикой и нелатинских — два или три, а многие эмодзи — четыре. Ни одна из пяти метрик здесь не является подсчётом байтов, поэтому для полей с ограничением по байтам сначала кодируйте в UTF-8.

Похожие инструменты

  • Конвертер размеров данных

    Ни один из счётчиков здесь не даёт размер в байтах: размер появляется только после того, как текст закодирован. Когда это число уже получено, там оно читается сразу в десятичных и двоичных единицах, и там же сказано, как его назовёт каждая операционная система.

  • Тестер регулярных выражений

    Проверка регулярных выражений — поиск, замена, разбиение.

  • Сравнение текстов

    Сравните два текста — каждая изменённая строка и слово.

  • Инспектор символов Unicode

    Узнайте, из каких именно символов состоит строка.