Только когда мы приходим к цели, мы решаем, что путь был верен (П. Валери).

Невидимые символы Unicode: как найти их в тексте


Невидимые символы Unicode: как найти их в тексте

Две строки выглядят одинаково, но сравнение возвращает false. Вставленный адрес не находится поиском, а после копирования фразы из документа между словами появляется странный разрыв. Прежде чем искать ошибку в базе данных или кодировке, стоит проверить сами символы: кроме букв и обычного пробела, строка может содержать знаки, которые почти не видны на экране.

Такие символы не обязательно означают повреждённые данные. Некоторые управляют переносом строк, другие участвуют в отображении письменности. Проблема возникает, когда приложение ожидает один набор символов, а получает другой.

Пробелы с разным поведением

Обычный пробел имеет код U+0020. Неразрывный пробел U+00A0 выглядит похоже, но удерживает соседние части текста на одной строке. Он полезен, например, между числом и единицей измерения. В технической строке, которую пользователь копирует из редактора, такая замена может оказаться неожиданной.

Пробел нулевой ширины U+200B не занимает видимого места. Он обозначает возможность переноса без привычного промежутка между буквами. Поэтому слово с этим знаком внутри может выглядеть цельным, хотя его последовательность кодовых точек отличается от исходной.

Отдельного внимания заслуживают U+200C и U+200D — знаки, управляющие соединением символов. Их используют в некоторых письменностях; U+200D также участвует в составных последовательностях эмодзи. Удалять их из любого пользовательского текста без разбора нельзя: после очистки может измениться его отображение.

Как увидеть содержимое строки в JavaScript

Для первичной диагностики удобно вывести кодовую точку каждого символа. Пример ниже создаёт строку с U+200B между двумя частями слова. В выводе появляется дополнительная запись, которую трудно заметить при обычном просмотре текста.

const text = 'user\u200Bname';

const points = Array.from(text, char =>
  'U+' + char.codePointAt(0)
    .toString(16)
    .toUpperCase()
    .padStart(4, '0')
);

console.log(points.join(' '));
// U+0075 U+0073 U+0065 U+0072 U+200B
// U+006E U+0061 U+006D U+0065

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

Почему trim и normalize не решают всё

Метод trim убирает определённые пробельные символы по краям строки. Он не предназначен для удаления любых невидимых знаков. Например, U+200B внутри слова останется на месте; рассчитывать на trim как на универсальную очистку нельзя.

Нормализация Unicode решает другую задачу: приводит определённые эквивалентные представления текста к выбранной форме. Вызов normalize(‘NFC’) не удаляет U+200B. При диагностике лучше отдельно проверять состав строки и отдельно решать, нужна ли нормализация.

Перед исправлением полезно ответить на три вопроса: откуда поступил текст, какие символы допустимы в конкретном поле и нужно ли сохранять исходное значение. Для артикула товара и для многоязычного имени пользователя ответы будут разными.

Как воспроизвести проблему в форме

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

Проверяйте результат не только сразу после вставки. Сохраните значение, повторно откройте форму и посмотрите, что вернул сервер. Клиентская проверка, обработка на сервере и повторное отображение могут по-разному менять одну и ту же строку.

Очищайте по правилам конкретного поля

Если поле допускает только латинские буквы, цифры и дефис, надёжнее проверять этот разрешённый набор и объяснять пользователю причину отказа. Для свободного текста столь жёсткое правило не подходит: оно отбросит нормальные символы других языков.

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

При сравнении внешне одинаковых строк начинайте с вывода кодовых точек. Это быстрый способ отделить ошибку обработки данных от различия в самих данных и выбрать исправление, которое не сломает остальной текст.

Редактор: AndreyEx

Если статья понравилась, поделитесь ей в социальных сетях

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

3 × один =

Это может быть вам интересно


Спасибо!

Теперь редакторы в курсе.

Прокрутить страницу до начала