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

Читать часть 1
Читать часть 3

В зависимости от вкусов пользователи захотят, чтобы их многоточие было или ýже, или шире, но где-нибудь в пределах двух крайностей, показанных на рисунке выше. Нет ничего проще: создадим специальную команду, которая будет разрежать три точки на некоторое расстояние. Чтобы не мучиться с прописыванием каждого расстояния вручную, для разрядки текста употребим пакет soul (его название происходит от space out и underline — двух главных функций, предоставляемых пакетом: разрядка и подчёркивание). Самые умненькие, пользующиеся юникодом и пишущие в кодировке UTF-8, должны подключить не soul, а soulutf8 (просто, правда?). После подключения проведём настройку разреженности букв:

\usepackage{soulutf8} % те, кто в cp1251 или в ещё более
% глубоком ужасе, пишут \usepackage{soul}
\sodef\so{}{.1em}{1em plus1em}{.3em plus.05em minus.05em}
\newcommand{\ldotst}{\so{...}}
\newcommand{\ldotsq}{\so{?..}}
\newcommand{\ldotse}{\so{!..}}

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

Что же конкретно делает этот пакет? Рассмотрим следующие несколько примеров. Условные обозначения: в левой колонке знаки обычного пробела для ясности обозначены знаком подчёркивания (но на самом деле я имел в виду под этим пробел, просто так виднее!). Как говорится, то лев, а не собака; веб-браузер криво отображает знак явного пробела... Далее, значком я обозначил межбуквенные пробелы (которые при стандартном наборе отсутствуют и возникают при разрядке), значком — внутренний пробел между разрежаемыми словами, значком * — внешний пробел.

Случай Ввод Вывод
1 Барин\so{набрал_в_рот}навозу Баринн•а•б•р•а•л●в●р•о•тнавозу
2 Барин_\so{набрал_в_рот}_навозу Барин*н•а•б•р•а•л●в●р•о•т*навозу
3 Барин_{\so{набрал_в_рот}}_навозу Барин*н•а•б•р•а•л●в●р•о•т*навозу
4 Барин_\null{\so{набрал_в_рот}}{}_навозу Барин_н•а•б•р•а•л●в●р•о•т_навозу

Случай 1: если пропустить внешние пробелы вокруг разрежаемого текста, то их так и не будет в разреженном варианте. Случай 2 — это то, что нам нужно: разреженный текст где-то посреди обычного, причём окружающие его пробелы будут не простыми, а специальными внешними, причём наличие группирующих скобок (случай 3) ни на что не влияет. Чтобы принудить систему выдать не внешний, а обычный пробел, то надо, как в случае 4, создать символ-ничего перед окружением; \kern0pt, \null или любой другой знак сойдут. Пробел после можно нормализовать при помощи \relax или \null.

Синтаксис команды \sodef таков: \sodef<\команда>{<шрифт>}{<межбуквенный пробел>}{<пробел внутри разрежаемого текста>}{<пробелы извне разрежаемого текста>}, или в терминах наших обозначений: \sodef<\кмнд>{<шрифт>}{•}{●}{\*}. Пробелы могут задаваться с клеем, то есть с диапазоном плюс-минус, в котором их можно подгонять под наилучшее отображение на строке. По умолчанию стоит одна конфигурация, которая вызывается командой \so и имеет следующие параметры:

\sodef\textso{}{.25em}{.65em\@plus.08em\@minus.06em}{.55em\@plus.275em\@minus.183em}

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

\sodef\so{}{.1em}{1em plus1em}{.3em plus.05em minus.05em}
\newcommand{\ldotst}{\so{...}}
\newcommand{\ldotsq}{\so{?..}}
\newcommand{\ldotse}{\so{!..}}

Естественно, длина интервала должна зависеть от размера шрифта (а не задаваться в пунктах и тем более в миллиметрах!). На мой взгляд, эти значения удовлетворят большинство искушённых пользователей. Желающие могут поиграться с параметрами или задействовать пакет xspace. Зачем? Потому что в текущем виде команду придётся употреблять в тексте так:

\ldotst и тотчас же забылся\ldotst{} Он очнулся в полные сумерки.
\ldotst и тотчас же забылся\ldotst\ Он очнулся в полные сумерки.

Если же к документу подключить пакет xspace, то можно будет сделать так:

\usepackage{xspace}
\newcommand{\ldotst}{\so{...}\xspace}
\ldotst{}и тотчас же забылся\ldotst Он очнулся в полные сумерки.

При этом пробел не будет съеден командой \ldotst.

Возникает незадача с \newcommand{\ldotsq}{\so{?..}\xspace}, так как по-прежнему вопросительный знак выглядит смещённым: расстояние между точками неодинаково. Чтобы восстановить справедливость, вручную сосчитаем, на какую длину нужно вручную сдвинуть вопросительный знак.

Для этого сгенерируем два PDF-файла с одной-единственной командой в самом теле — \ldotsq, но по очереди используем в преамбуле две следующие хитрые конструкциями.

Преамбула 1: \newcommand{\ldotsq}{\so{?\hbox{\hspace{0em}}..}\xspace}

?.. with 0em box

Преамбула 2: \newcommand{\ldotsq}{\so{?\hbox{\hspace{1em}}..}\xspace}

?.. with 1em box

Естественно, результат будет ужасным. В первом случае из-за наличия коробки \hbox вопросительный знак будет смотреться ещё смещёнее, а второй результат... не пугайтесь, это временная мера. Снимите оба скриншота (желательно, чтобы знаки почти совпадали... началом) и вставьте в свой любимый редактор (Photoshop или Paint сойдут). На кадре, где добавлен 1em горизонтального пространства, правая точка вообще закатилась за правый край скриншота. Теперь возьмём инструмент «прямоугольное выделение» (Rectangular Marquee) и измерим расстояние между краями (например, левыми... или правыми, в зависимости от политических убеждений) левой точки (от вопросительного знака) и центральной (которая первая самостоятельная) в обоих случаях. Вычтем из второго измерения первое. Это мы измерили расстояние в 1em в пикселях (так как в первом случае был сдвиг на 0em, во втором — на 1em). В моём случае вышло, что при таком гигантском разрешении (6400%) один em равен 849 пикселям (если этого нигде не написано, то попробуйте нажать F8 или выбрать отображение панели Window — Info, на которой показывается размер выделения в выставленных в параметрах единицах; в Paint достаточно посмотреть в левый нижний угол, и это верно для Windows 7). Самые умненькие (навроде меня) могли сделать по-другому: поставить режим отображения Darken и провести всего одно измерение. Теперь смотрим на скриншот, на котором расстояние сдвига равно 0em, и измеряем расстояния между первой и второй и между второй и третьей точками. Получилось 501 и 320,5 (так как читающий это уже сам по себе индивидуальность, у него могут получиться совершенно иные цифры). Простая арифметика говорит, что необходимо сократить расстояние между вопросительным знаком и первой точкой на (501 − 320,5) / 849 = 0,212 долей целого em (больше знаков после запятой добавлять нет смысла из-за погрешности; так, я получал результаты 0,2106, 0,2126 и 0,2133, но человеческий глаз столь тонкой разницы ощутить уже не может).

Выполняем подстановку:

\newcommand{\ldotsq}{\so{?\hbox{\hspace{-.212em}}..}\xspace}

Полученную картинку проверяем в графическом редакторе на вшивость: результаты в 320 и 321 пиксель более чем устраивают (1 пиксель уходит на субпиксельное сглаживание и погрешности), ошибка менее половины процента от ширины буквы M.

?.. after hspace shift

При использовании других размеров или начертаний шрифта или других шрифтов получаются другие результаты. Кроме того, при изменении самого расширения (если нам хочется более плотных или более далеко отстоящих друг от друга точек) надо не забывать включать изменение в команду \ldotsq: если написано не \sodef\so{}{.1em}..., а \sodef\so{}{.15em}... (более широкое многоточие), то в команде \hbox горизонтальный сдвиг должен быть не -.212em, а -.262em.

Использовать \xspace нужно только в том случае, если после многоточия должен обязательно идти пробел. Если не принять никаких дополнительных мер, то тогда станут невозможными конструкции навроде <...> или (Я этого так хочу...), так как после вёрстки пробел будет добавляться автоматически: <... >; (Я этого так хочу... ). Это в корне некорректно. Чтобы этого избежать, необходимо прописать декларацию свободы специальных знаков от пробела (в частности, всевозможных закрывающих) при помощи команды \xspaceaddexceptions. В аргументе команды должны стоять команды или символы, перед которыми необходимо запретить своевольное добавление пробела (при этом ничто не мешает пользователю добавить его вручную).

Итак, истинные аристократы, гурманы и библиофилы, возжелав иметь у себя самое точное и непогрешимо эстетичное многоточие, должны в свою преамбулу включить следующую мантру:

\usepackage{soulutf8,xspace} % у кого не UTF-8, те пишут просто soul
\xspaceaddexceptions{ < ) }
\sodef\so{}{.1em}{1em}{.3em plus.05em minus.05em}
\newcommand{\ldotst}{\so{...}\xspace}
\newcommand{\ldotsq}{\so{?\hbox{\hspace{-.212em}}..}\xspace}
\newcommand{\ldotse}{\so{!..}\xspace}

Comparison of 3 different ellipses

Читать продолжение!