3.04. Текстовые данные
Разработчику
Аналитику
Тестировщику
Архитектору
Инженеру
Текстовые данные
Текстовые данные — это последовательности символов, предназначенные для хранения, передачи и интерпретации информации в форме, читаемой человеком или обрабатываемой программами. В отличие от числовых, бинарных или мультимедийных данных, текст обладает особой структурной и семантической гибкостью: он может быть носителем естественного языка, программного кода, разметки, команд, метаданных и даже графических примитивов (например, эмодзи). Эта глава посвящена устройству текста как информационного объекта — от его физического представления в памяти до способов восприятия и интерпретации как людьми, так и программными системами.
Какими бывают текстовые данные
Текстовые данные классифицируются не по содержанию, а по структуре, назначению и уровню формализации. В повседневной практике программиста, системного администратора или технического писателя можно выделить следующие категории:
-
Простой (плоский) текст — последовательность символов без встроенных команд форматирования. Примеры: файлы
.txt, исходные коды программ, логи приложений. Такой текст обрабатывается универсально, не требует специальных интерпретаторов и сохраняет совместимость между платформами при соблюдении кодировки. -
Структурированный текст — содержит явные элементы организации: теги, разделители, иерархические блоки. К нему относятся XML, JSON, YAML, TOML, CSV (при строгом соблюдении формата). Такой текст допускает автоматизированное извлечение значений, валидацию схемы и трансформацию. Его структура задаётся синтаксическими правилами, а не только смыслом.
-
Полуструктурированный текст — сочетает свободную форму повествования с вкраплениями формализованных фрагментов. Примеры: электронные письма с заголовками в формате RFC 5322, документы Markdown, HTML-страницы с встроенным JavaScript или CSS. Здесь структура может быть локальной и не охватывать весь документ целиком.
-
Размеченный текст — несёт информацию не только о содержании, но и о его представлении или семантике. В отличие от простого текста, разметка содержит инструкции для движков отображения или обработки: например,
<strong>в HTML указывает на семантическую важность фрагмента, а**в Markdown — на визуальное выделение. Разметка может быть декларативной (как в LaTeX), императивной (как в RTF) или гибридной. -
Исходный код — особый вид текста, предназначенный для интерпретации или компиляции в исполняемые инструкции. Хотя синтаксически он может напоминать структурированный или размеченный текст, его ключевое отличие — строгая грамматика и привязка к конкретной вычислительной модели. Ошибки в коде могут приводить не к искажению представления, а к сбою выполнения.
-
Мета- и служебные тексты — например, HTTP-заголовки,
.gitignore, файлы локализации (.properties,.po), инструкции сборки (Makefile,Dockerfile). Такие тексты управляют поведением инструментов, но не предназначены для непосредственного чтения пользователем.
Важно понимать: границы между этими типами условны. Один и тот же текст может одновременно быть исходным кодом, структурированным документом и размеченным контентом — например, HTML-файл с встроенным <script> и <style>.
Как устроен текст
На самом низком уровне текст — это последовательность кодов, каждый из которых соответствует определённому графему (условной единице письменности). Графема может быть буквой, цифрой, знаком препинания, управляющим символом или составным элементом (например, буквой с диакритикой). Совокупность всех допустимых графем и их кодов образует кодировку символов.
Однако кодировка — не единственный уровень абстракции. Между человеком и машиной действует цепочка преобразований:
- Графема — абстрактное понятие (например, «латинская заглавная A»).
- Символьный код — целочисленное значение в рамках стандарта (например, U+0041 в Unicode).
- Кодовая единица — физическое представление кода в памяти (например, байт
0x41в UTF-8 или два байта0x00 0x41в UTF-16BE). - Глиф — визуальное воплощение символа, предоставляемое шрифтом (например, изображение «A» в шрифте Times New Roman).
Эта цепочка показывает, что текст — не монолитный объект, а результат согласованной работы нескольких подсистем: кодировочной таблицы, транскодера, шрифтового рендерера и интерпретатора разметки. Нарушение на любом этапе приводит к искажению: замене символа, отображению заглушки («□» или «») или полному сбою парсинга.
Строка и текст — в чём различие
В теории и практике программирования часто разделяют понятия строки и текста, хотя в бытовом употреблении они синонимичны.
-
Строка — это структура данных: упорядоченный неизменяемый (в большинстве языков) контейнер, хранящий последовательность кодовых единиц в определённой кодировке. Строка не несёт информации о языке, направлении письма, семантической роли слов. Для машины строка
"123"идентична строке"abc"— обе представляют собой массив байтов или слов. Операции над строками (конкатенация, подстрока, поиск) производятся на уровне кодов, без учёта лингвистики. -
Текст — это строка в контексте интерпретации. Текст предполагает наличие читателя — человека или алгоритма, способного извлечь смысл. Для текста важны: язык (для морфологического разбора), регистр (для восприятия тональности), пунктуация (для синтаксического анализа), направление (например, арабский или иврит пишутся справа налево), а также культурные конвенции (например, использование кавычек «ёлочкой» в русском vs „Gerade“ в немецком).
Таким образом, строка — это носитель, текст — содержание. Пример: строка "\u043F\u0440\u0438\u0432\u0435\u0442" в UTF-16 — это просто шесть 16-битных значений. Но в контексте русского языка она становится текстом «привет» — с определённым смыслом, интонацией приветствия и культурной маркировкой.
Структурированный и неструктурированный текст
Разделение на структурированный и неструктурированный текст — ключевое для проектирования систем хранения и обработки.
Неструктурированный текст — это последовательность символов без явных правил организации. К нему относятся художественные произведения, деловая переписка, записи в блогах, комментарии в коде. Такой текст требует применения методов обработки естественного языка (NLP): токенизации, именованного распознавания сущностей, классификации тональности. Его анализ трудоёмок и не всегда детерминирован.
Структурированный текст подчиняется строгой грамматике. Например, в JSON каждое значение должно быть одним из типов: строка в двойных кавычках, число, логическое значение, null, массив или объект. Наличие запятой в конце последнего элемента массива делает документ невалидным — система откажет в парсинге. Структурированность позволяет:
- однозначно извлекать данные без двусмысленности;
- строить схемы валидации (JSON Schema, XSD);
- генерировать клиентский код по контракту (например, через OpenAPI);
- осуществлять сериализацию/десериализацию с гарантией обратимости.
Между этими полюсами находится полуструктурированный текст. Он не требует полной формализации, но использует локальные шаблоны. Пример — лог-файл в формате:
[2025-11-20T12:34:56.789Z] INFO User login: timur@example.com
Здесь дата, уровень и событие выделены по позиции и разделителям. Такой текст можно парсить регулярными выражениями или специализированными парсерами, но небольшое изменение формата (например, добавление микросекунд) может нарушить обработку.
Важно: структурированность — не свойство текста как такового, а договорённость о формате между производителем и потребителем. Один и тот же физический файл может быть структурированным для одной системы (например, парсера логов) и неструктурированным для другой (например, поискового индексатора, который индексирует всё как сплошной поток токенов).
Кодировка
Кодировка (encoding) — это соглашение о том, каким образом символы естественного или формального языка отображаются в последовательность байтов для хранения или передачи. Кодировка определяет не только соответствие «символ ↔ число», но и способ кодирования этого числа в байты — особенно в случае многобайтовых систем.
ANSI и однобайтовые кодировки
Термин ANSI в контексте Windows исторически используется для обозначения однобайтовых кодовых страниц, таких как Windows-1251 (кириллица), Windows-1252 (западноевропейская латиница) или CP866 (DOS-кодировка). В этих системах один символ представлен ровно одним байтом, что даёт максимум 256 возможных значений. Однако 256 позиций недостаточно для одновременного представления нескольких алфавитов — поэтому возникали кодовые страницы: переключение набора символов в зависимости от локали. Например, байт 0xC0 в CP866 — это буква «А», в Windows-1251 — тоже «А», а в ISO-8859-1 — символ À. Отсутствие явного указания кодовой страницы в файлах приводило к широко известной проблеме «кракозябр»: открытие текста в неверной локали искажало содержимое.
Однобайтовые кодировки обладают рядом технических ограничений: невозможность смешивать языки (например, русский и греческий), отсутствие поддержки диакритики вне узкого региона, несовместимость между платформами. Несмотря на это, они сохраняют актуальность в legacy-системах, особенно в промышленных протоколах (Modbus ASCII, некоторые SCADA-интерфейсы), где экономия каждого байта критична.
Unicode и его кодировки: UTF-8, UTF-16, UTF-32
Unicode — не кодировка, а стандарт кодирования символов, определяющий уникальный числовой идентификатор (code point) для каждого графема. На момент 2025 года Unicode охватывает более 150 тысяч символов: алфавиты современных и древних языков, математические обозначения, символы игр, технические знаки, эмодзи и даже управляющие последовательности (например, для направления письма).
Сам по себе code point — абстрактное число, например U+0410 для «А» (кириллической), U+1F600 для «😀». Чтобы записать его в память, требуется конкретная кодировка. Основные варианты:
-
UTF-32 — каждый code point представлен 32-битным целым числом (4 байта). Это простейшая схема: индексация по символам тривиальна, длина строки в символах равна длине массива. Однако она неэффективна по памяти: латинские символы занимают 4 байта вместо 1. Применяется редко — в основном в внутренних буферах движков, где важна скорость доступа.
-
UTF-16 — использует 16-битные кодовые единицы. Символы из базовой многоязычной плоскости (BMP, U+0000–U+FFFF) кодируются одним юнитом. Символы выше (например, большинство эмодзи, U+10000–U+10FFFF) — парой суррогатных юнитов (high surrogate + low surrogate). Это приводит к тому, что длина строки в «юнитах» не совпадает с числом графем. Например, строка
"👩💻"(женщина-разработчик) состоит из 7 code points, но в UTF-16 может занимать 11 юнитов. Именно поэтому методы вродеString.lengthв JavaScript илиlen()в Java (до Java 15) могут давать неожиданные результаты. UTF-16 — родная кодировка для Windows API, Java (внутренне) и .NET (вstring), что обусловлено историческими причинами (первоначальная версия Unicode предполагала 16-битный охват). -
UTF-8 — переменной длины, совместимая с ASCII. Символы в диапазоне U+0000–U+007F (латиница, цифры, пунктуация ASCII) кодируются одним байтом, идентичным их ASCII-коду. Это обеспечивает обратную совместимость: любой ASCII-файл автоматически является корректным UTF-8. Далее:
- U+0080–U+07FF — 2 байта,
- U+0800–U+FFFF — 3 байта (весь BMP, включая кириллицу, греческий, арабский),
- U+10000–U+10FFFF — 4 байта (эмодзи, древние письменности).
UTF-8 стал де-факто стандартом для веба (более 98 % страниц по данным W3Techs), UNIX-систем, JSON, XML, протоколов (HTTP, SMTP) и большинства современных форматов. Её преимущества: компактность для латиницы, устойчивость к повреждениям (ошибка в одном байте не портит весь поток), отсутствие проблемы порядка байтов (endianness). Недостаток — сложность прямой индексации: чтобы перейти к n-му символу, нужно последовательно декодировать все предшествующие.
BOM и порядок байтов
В многобайтовых кодировках (особенно UTF-16 и UTF-32) возникает вопрос: в каком порядке хранить байты — старший сначала (big-endian, BE) или младший (little-endian, LE)? Чтобы избежать неоднозначности, может использоваться Byte Order Mark (BOM) — специальный невидимый символ U+FEFF в начале потока. Его кодировка указывает порядок: в UTF-16BE BOM — 0xFE 0xFF, в UTF-16LE — 0xFF 0xFE. В UTF-8 BOM (0xEF 0xBB 0xBF) не нужен, так как порядок байтов фиксирован, но он иногда добавляется Windows-редакторами для явной идентификации кодировки. Это может вызывать проблемы: например, PHP-скрипты с BOM в начале файла выдают «headers already sent», так как BOM интерпретируется как вывод.
Преобразование кодировок и совместимость
Преобразование текста из одной кодировки в другую — операция транскодирования. Она требует знания исходной кодировки; без этого данные неотличимы от произвольного бинарного шума. Большинство современных библиотек (ICU, iconv, .NET Encoding, Python str.encode()) поддерживают конвертацию через Unicode: исходная кодировка → Unicode code points → целевая кодировка. При этом возможна потеря информации: если целевая кодировка не содержит нужного символа, он заменяется заглушкой (например, ? или ``), либо возникает исключение.
Важный нюанс: объявление кодировки (например, <meta charset="utf-8"> в HTML или # -*- coding: utf-8 -*- в Python) не меняет физическое содержимое файла — оно лишь указывает интерпретатору, какой схемой декодировать байты. Если объявление не совпадает с фактической кодировкой, результат будет искажён. Для надёжного определения кодировки используются эвристики (анализ частотности байтов, проверка на валидность UTF-8) и сигнатуры (BOM, XML-декларация <?xml encoding="..."?>).
Шрифты
Шрифт — это набор графических описаний (глифов), сопоставленных символьным кодам. Шрифт не определяет значение символа — только его внешний вид. Один и тот же code point может отображаться по-разному в разных шрифтах: например, U+0061 (латинская a) в шрифте Courier выглядит моноширинной и угловатой, а в Comic Sans — округлой и неформальной.
Как работает шрифт
Современные шрифты (в основном форматов TrueType — .ttf и OpenType — .otf) содержат:
- Таблицу cmap — сопоставление code point → идентификатор глифа.
- Описание глифа — либо в виде векторных контуров (Bézier-кривые), либо в виде растровых битмапов (для малых размеров).
- Метрики — кернинг (расстояние между конкретными парами символов), вынос (расстояние от базовой линии до верхней/нижней границы), интерлиньяж.
- OpenType-функции — лигатуры (например,
fi→ «fi»), альтернативные формы, поддержка сложных сценариев (арабский, деванагари).
Рендеринг текста — многоэтапный процесс:
- Формирование строки — с учётом направления письма (LTR/RTL), объединения символов (например, буква + диакритика → один глиф), замены лигатур.
- Выбор шрифта — по стеку шрифтов: если текущий шрифт не содержит глифа для code point, система ищет его в резервных (fallback fonts).
- Глиф-рендеринг — векторные контуры растрируются в битмап с учётом размера, сглаживания (hinting, subpixel rendering), цвета.
- Композитинг — наложение глифов на фон, применение эффектов (тень, обводка).
В системах с ограниченными ресурсами (встроенные ОС, старые браузеры) используют растровые шрифты (.fon в Windows, bitmap fonts в Linux), где каждый размер хранится отдельно — это экономит CPU, но увеличивает объём.
Установка шрифтов
-
Windows: копирование
.ttf/.otfвC:\Windows\Fonts(через Проводник или PowerShellCopy-Item). Шрифты становятся доступны всем приложениям после обновления кэша (fontcache). -
Linux (десктоп): шрифты помещают в
~/.local/share/fonts/(для пользователя) или/usr/share/fonts/(глобально), затем вызываютfc-cache -fvдля обновления кэша Fontconfig. Конфигурация черезfonts.confпозволяет задавать приоритеты, алиасы, замены. -
Android: системные шрифты — часть AOSP (
/system/fonts). Приложения могут включать собственные шрифты вassets/fonts/и подключать их черезTypeface.createFromAsset(). -
Веб-разработка: шрифты подключаются через CSS-правило
@font-face:@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2'),
url('/fonts/custom.woff') format('woff');
font-display: swap; /* управляет поведением при загрузке */
}Форматы WOFF/WOFF2 — сжатые обёртки над OTF/TTF, оптимизированные для сети.
font-displayопределяет, показывать ли запасной шрифт во время загрузки (swap), скрывать текст (block) или использовать системный (fallback).
Важно: веб-шрифты подлежат CORS-проверке — сервер должен отправлять заголовок Access-Control-Allow-Origin. Кроме того, лицензии на шрифты часто ограничивают их встраивание в веб.
Таблицы символов, CHARMAP и «кракозябры»
Таблица символов в Windows: Character Map
Утилита charmap.exe предоставляет графический интерфейс к установленным шрифтам. Она позволяет:
- Просматривать все глифы шрифта;
- Копировать символы в буфер (включая недоступные на клавиатуре:
§,©,→); - Видеть Unicode-код (например,
U+2192для →); - Выбирать подмножество (латиница, кириллица, математические символы).
CHARMAP не изменяет кодировку текста — он лишь помогает ввести нужный символ. Сам текст далее обрабатывается по тем же правилам, что и любой другой.
Природа «кракозябр» и иероглифов
«Кракозябры» — визуальный эффект неправильной интерпретации байтовой последовательности. Возникает, когда:
-
Текст сохранён в кодировке A, но прочитан как кодировка B. Например, UTF-8-последовательность
0xD0 0x90(кириллическая «А») интерпретирована как Windows-1252:0xD0→Ð,0x90→ неразрывный пробел (отображается как `` или пропуск) — получаемÐ. -
Отсутствует шрифт с нужным глифом. Символ существует в кодировке, но рендерер не может его нарисовать — показывается placeholder (□, , [?]).
-
Использованы управляющие символы. Например,
U+202E(RIGHT-TO-LEFT OVERRIDE) может «перевернуть» отображение строки:"exe.txt txt.exe"→exe.txt txt.exe(вторая часть пишется справа налево, создавая иллюзию подмены расширения — метод фишинга).
«Иероглифы» в бытовом смысле — не обязательно китайские иероглифы, а любой текст, написанный алфавитом, незнакомым пользователю. С технической точки зрения, это корректный текст в соответствующей кодировке (чаще всего UTF-8), просто отсутствует лингвистическая компетенция для его интерпретации.
Эмодзи
Эмодзи — это символы Unicode, предназначенные для передачи эмоций, объектов и действий. Первые эмодзи были стандартизированы в Unicode 6.0 (2010), сейчас их более 3700.
Как работают эмодзи
Эмодзи — не изображения, а code points. Например:
U+1F600— 😀 Grinning Face;U+1F469 U+200D U+1F4BB— 👩💻 Woman Technologist (составной: женщина + zero-width joiner + компьютер).
Особенности:
-
Варианты отображения: многие эмодзи имеют текстовый (
U+FE0E) и эмодзи-вариант (U+FE0F). Например,U+2764 U+FE0E→ ❤ (чёрное сердце как символ),U+2764 U+FE0F→ ❤️ (цветное сердце-эмодзи). Без варианта выбор зависит от шрифта и платформы. -
Скин-тоны: эмодзи с людьми могут модифицироваться肤色 modifiers (U+1F3FB–U+1F3FF), добавляемыми после основного символа.
-
Составные эмодзи: используют zero-width joiner (
U+200D) для объединения базовых символов (👨👩👧👦 = U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466).
Отрисовка эмодзи зависит от шрифта эмодзи, встроенного в ОС: Apple Color Emoji (macOS), Segoe UI Emoji (Windows), Noto Color Emoji (Android, Linux). Веб-браузеры используют системный шрифт по умолчанию.
Ввод эмодзи
- Windows:
Win + .(точка) илиWin + ;вызывает панель эмодзи с поиском, историей, каракулями (sketch-to-emoji). - macOS:
Cmd + Ctrl + Space. - Android/iOS: отдельная клавиша на экранных клавиатурах.
- Linux: через
ibus-emoji(вводCtrl+Shift+E, затем код или название).
Эмодзи допустимы в:
- Именах файлов (но не рекомендуются — проблемы с legacy-системами);
- URL (требуется percent-encoding, например,
😀→%F0%9F%98%80); - JSON/XML (если кодировка UTF-8);
- Исходном коде (в строковых литералах, комментариях; в идентификаторах — только в языках с поддержкой Unicode, например, Python 3, C#).
Регистр: не только вопрос вида
Регистр — свойство буквенного символа, указывающее на его форму: прописную (заглавную) или строчную. В Unicode регистр определяется не для всех символов — только для тех, где это лингвистически осмысленно (латиница, кириллица, греческий и др.). Для каждого символа с регистром заданы три операции:
- toUpper — преобразование в верхний регистр,
- toLower — в нижний,
- toTitle — в заголовочный (первая буква слова — прописная, остальные — строчные, как в названиях глав).
Регистровые преобразования не всегда однозначны и зависят от языка. Например, в турецком языке латинская i в верхнем регистре — не I, а İ (I с точкой), а ı (i без точки) → I. Поэтому корректные библиотеки (например, ICU в Java, String.prototype.toLocaleUpperCase() в JavaScript) требуют указания локали: "i".toLocaleUpperCase('tr-TR') → "İ".
Технически регистр реализован через таблицы case mapping в стандарте Unicode. Каждый code point имеет (если применимо):
Simple_Uppercase_Mapping,Simple_Lowercase_Mapping,Special_Casing(для контекстно-зависимых правил, например, немецкогоß→SSв верхнем регистре).
Важно отличать визуальный регистр (начертание шрифта: small caps) от семантического (фактическое изменение code point). CSS-свойство text-transform: uppercase меняет отображение, но не содержимое DOM: document.querySelector('p').textContent вернёт исходный регистр. Для изменения данных требуется программное преобразование строки.
Раскладка клавиатуры
Раскладка клавиатуры — это таблица соответствия между физическими клавишами (и их модификаторами: Shift, AltGr) и генерируемыми символьными кодами. Раскладка не связана напрямую с кодировкой: одна и та же раскладка может использоваться в системах с разной кодовой страницей, а один и тот же символ может вводиться разными комбинациями в разных раскладках.
Стандартные раскладки:
- QWERTY — латинская, доминирующая в англоязычных странах и де-факто глобально.
- ЙЦУКЕН — кириллическая, принятая в России и странах СНГ.
- AZERTY — французская, с переставленными клавишами и упрощённым доступом к диакритике.
- Colemak/Dvorak — альтернативные эргономичные раскладки.
Механизм работы:
- При нажатии клавиши ОС получает скан-код — номер физической клавиши (например,
0x1E— клавиша «A» на PS/2). - Драйвер клавиатуры, учитывая текущую раскладку и нажатые модификаторы, преобразует скан-код в виртуальный код (VK) и символьное сообщение (WM_CHAR в Windows,
keyvalв X11). - Приложение получает Unicode code point (в современных системах) или код в локальной кодовой странице (в legacy-приложениях).
Смена раскладки может быть:
- глобальной (на уровне ОС, действует для всех приложений),
- прикладной (например, в редакторе кода: английская для кода, русская для комментариев),
- контекстной (автоматическое переключение по языку ввода, как в Gboard).
В Linux управление раскладками осуществляется через XKB (X Keyboard Extension), в Windows — через Language Bar и API LoadKeyboardLayout. Для разработчиков важно: обработка ввода должна опираться на символьные события, а не на скан-коды — иначе приложение будет некорректно работать в не-QWERTY раскладках.
Пробелы и отступы: невидимая структура текста
Пробел — не единый символ, а класс whitespace-символов, каждый со своим назначением:
| Code Point | Имя | Назначение |
|---|---|---|
U+0020 | SPACE | Обычный пробел — разделитель слов, сжимаемый в HTML. |
U+00A0 | NO-BREAK SPACE (NBSP) | Неразрывный пробел: предотвращает перенос («гл. 5», «100 руб.»). |
U+2002 | EN SPACE | Ширина буквы «N» — используется в типографике. |
U+2003 | EM SPACE | Ширина буквы «M» — для крупных отступов. |
U+2009 | THIN SPACE | Узкий пробел — между цифрой и единицей измерения (если разрешено ГОСТ). |
U+202F | NARROW NBSP | Узкий неразрывный (например, в «10 000 руб»). |
U+205F | MEDIUM MATHEMATICAL SPACE | В формулах (редко используется). |
Отступы (indentation) — средство структурирования текста. Различают:
-
Символьные отступы: табуляция (
U+0009,U+000B,U+000C) или пробелы (U+0020). В исходных кодах предпочтение отдаётся пробелам (PEP 8, Google Style Guides), так как табуляция зависит от настроек редактора (ширина таба = 2, 4, 8 пробелов). Смешивание табов и пробелов в одном файле приводит к ошибкам (например,IndentationErrorв Python). -
Семантические отступы: в Markdown и reStructuredText отступы задают вложенность списков или блоков кода. В HTML они не влияют на отображение (кроме
<pre>), но улучшают читаемость разметки. -
Типографские отступы: вёрстка использует CSS-свойства
text-indent(красная строка),margin,padding. Эти отступы управляются не текстом, а стилями.
Особый случай — нулевая ширина: символы U+200B (ZERO WIDTH SPACE), U+200C (ZERO WIDTH NON-JOINER), U+200D (ZERO WIDTH JOINER). Они не занимают места, но влияют на поведение: разрешают перенос (U+200B), запрещают лигатуру (U+200C) или создают составные эмодзи (U+200D).
Синтаксис текста и разметка
Синтаксис — набор правил, определяющих допустимую структуру текстового формата. Синтаксис может быть:
-
Контекстно-свободным — описывается формальной грамматикой (например, BNF, EBNF). К нему относятся большинство языков программирования, JSON, XML.
-
Контекстно-зависимым — требует дополнительной информации для проверки (например, HTML: тег
<li>допустим только внутри<ul>или<ol>; отступы в Python влияют на семантику). -
Эвристическим — не имеет строгой спецификации, интерпретируется по принципу «лучшего соответствия». Примеры: логи, email-заголовки, некоторые конфигурационные файлы.
Разметка — способ внедрения синтаксических конструкций в текст для управления его представлением или семантикой. Основные парадигмы:
-
Теговая (tag-based) — элементы окружены парными или самозакрывающимися тегами:
<p>Абзац</p>,<br/>,<div id="main">.
Примеры: HTML, XML. Требует балансировки тегов и экранирования (<вместо<). -
Декларативная (markup by convention) — синтаксис основан на позиции и символах:
# Заголовок,* Список,`код`.
Примеры: Markdown, reStructuredText. Лёгок для чтения в исходнике, но сложен для парсинга (много двусмысленностей:*italic*vs* список). -
Императивная — команды указывают, как рендерить текст:
{\bf Жирный},\section{Глава}.
Пример: LaTeX. Обладает точным контролем, но высоким порогом входа. -
Гибридная — сочетает подходы. Например, HTML-фрагменты внутри Markdown (допускаются, но не всегда рекомендуются).
Ключевой принцип современной разметки — семантическая разметка: теги должны описывать роль контента, а не его внешний вид. Например, <strong> (важно) предпочтительнее <b> (жирный), потому что первое сохраняет смысл при смене стилей или чтении скринридером.
Парсинг строк и текста
Парсинг — процесс анализа текста с целью извлечения структуры или значений. В зависимости от задачи и формата применяются разные техники:
-
Разделение по разделителю —
split(',')для CSV (устаревший, ненадёжный способ: не учитывает кавычки, переносы). -
Регулярные выражения — мощный инструмент для извлечения паттернов (
\d{4}-\d{2}-\d{2}для дат). Однако регулярки не справляются с вложенными структурами (например, HTML-тегами внутри атрибутов). -
Конечные автоматы — используются в лексическом анализе (токенизации): сканер проходит по строке, меняя состояние в зависимости от символа («вне строки», «внутри строки», «в комментарии»).
-
Рекурсивный спуск (recursive descent) — ручная реализация парсера по грамматике. Подходит для простых DSL.
-
LL/LR-парсеры — генерируются из грамматики (ANTLR, Bison). Обеспечивают строгую проверку синтаксиса и построение AST (абстрактного синтаксического дерева).
-
DOM-парсеры — для XML/HTML: строят древовидную модель документа, поддерживают XPath, валидацию DTD/XSD.
Парсинг текста всегда начинается с токенизации — разбиения на лексемы (токены): идентификаторы, литералы, операторы, ключевые слова. Затем следует синтаксический анализ — построение структуры по правилам грамматики. Ошибки на любом этапе приводят к исключениям (SyntaxError, ParseException) или некорректному AST.
Важно: парсинг — не то же самое, что валидация. Парсер может успешно построить дерево из формально валидного, но семантически бессмысленного текста (например, int x = "text"; в C# — синтаксически корректно, но семантически ошибка).
Форматирование текста
Современные системы различают логическое (семантическое) форматирование и визуальное. Первое закладывается в разметку, второе — в стили или рендеринг.
Жирный, курсив, подчёркнутый, зачёркнутый
-
Жирный (
<strong>,**текст**) — указывает на повышенную важность. В HTML по умолчанию рендерится какfont-weight: bold, но стили можно переопределить. -
Курсив (
<em>,*текст*) — выделяет акцент, иностранные слова, термины. По умолчанию —font-style: italic. -
Подчёркивание (
<u>) — исторически означало гиперссылку. Сейчас используется редко (путает пользователей), но допустимо для орфографических ошибок (<u class="spelling-error">). -
Зачёркивание (
<s>,~~текст~~) — устаревшая, недействительная или отменённая информация.
Все эти элементы — семантические теги, а не просто инструкции по отрисовке. Скринридеры озвучивают их особым образом («strong», «emphasized»), что критично для доступности.
Цитата
Цитата — выделение чужого высказывания. Различают:
- Блок цитаты (
<blockquote>) — для объёмных фрагментов. Может содержать атрибутciteс URL источника. - Строчная цитата (
<q>) — для коротких фраз внутри абзаца. Браузеры автоматически добавляют кавычки в соответствии с локалью.
Моноширинный текст
Моноширинное начертание (<code>, `код`, <pre>) используется для:
- фрагментов программного кода,
- терминальных команд,
- имён файлов и переменных,
- данных в фиксированной ширине (логи, таблицы ASCII-art).
Ключевые особенности:
- в
<pre>сохраняются пробелы и переносы строк; - внутри
<code>допустима вложенная разметка (например,<code>int <var>x</var> = 0;</code>).
Скрытый текст
Скрытый текст — содержимое, не отображаемое по умолчанию, но доступное программно или при определённых условиях. Реализуется через:
display: none(полное исключение из потока),visibility: hidden(сохраняет место, но невидим),aria-hidden="true"(скрытие от скринридеров, но видимость визуально).
Важно: скрытый текст не должен использоваться для манипуляций с поисковыми системами («cloaking»), что нарушает требования Google.
Гиперссылки
Гиперссылка (<a href="...">) — основной элемент гипертекста. Атрибуты:
href— целевой URI (относительный или абсолютный);target="_blank"— открытие в новой вкладке (требуетrel="noopener"для безопасности);rel="nofollow"— указание поисковикам не передавать вес;download— принудительная загрузка файла вместо навигации.
Для доступности:
- текст ссылки должен быть осмысленным вне контекста (не «нажмите здесь»);
- избегать ссылок из одного символа (
[1]); - использовать
aria-label, если визуальный текст неполон.