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

Классы невидимых символов
Символ, который не отображается на экране, управляющий символ и форматный символ не образуют единого взаимозаменяемого класса. Контекст определяет, как рендерер или протокол трактуют каждый код: один и тот же скаляр может быть пробелом для парсера и управляющим знаком для терминала. Unicode описывает свойства White_Space и General_Category=Cc как пересекающиеся множества, а не как разделённые группы. Табуляция U+0009 и перевод строки U+000A одновременно принадлежат обоим свойствам. Пробел U+0020 входит в White_Space, но не является управляющим. Невидимый разделитель слов U+200B не относится ни к одному из этих двух свойств, хотя и не отображается. Проверка конкретного скаляра по справочным таблицам свойств даёт однозначный ответ, тогда как угадывание по внешнему виду не даёт ничего.
Переносы строк и выбранная грамматика
Символы U+000D и U+000A встречаются в разных комбинациях в зависимости от формата файла или платформы. Последовательность CRLF и одиночный LF оба варианта распространены; утверждать, что современные системы преимущественно используют один из них, без указания конкретного формата нельзя. Корректный конвейер начинает с явного выбора входной грамматики: какие последовательности кодовых точек признаются границами строк, какие последовательности считаются ошибкой, а какие сохраняются как данные. После этого выбор фиксируется в документации или в конфигурации парсера, и дальнейшая обработка опирается на него, а не на предположения о происхождении текста.
Кодовые точки и байты
В UTF-32LE каждый скаляр занимает четыре байта, и последовательность кодовых точек U+0041, U+0009, U+0042, U+000D, U+000A, U+0043, U+0009, U+0044 превращается в тридцать два байта. Смешивать эти два представления ведёт к ошибкам: сдвиг на один байт в потоке ломает все последующие скаляры. NUL-терминация, то есть завершение строки нулевым байтом, является соглашением конкретного программного интерфейса, а не общим свойством всех буферов. Буфер, переданный между функциями, может не содержать завершающего NUL, и код, ожидающий его, получит мусор за границей данных.
Пример разбора
Возьмём последовательность из восьми скаляров, приведённую выше, и зададим грамматику: CRLF означает конец строки, табуляция разделяет поля, все остальные невидимые символы сохраняются как данные. Разбор даёт две строки: первая содержит A и B, разделённые табуляцией, вторая содержит C и D. Табуляции не удаляются, а перевод строк не интерпретируется как одиночный LF, потому что грамматика выбрана заранее. Если бы в тексте встретился U+200B, он остался бы в поле без изменения, поскольку формат не предписывает его обработки.