> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/uk/dokladni-statti/47-tex-tables-how-tex-calculates-spanned-column-widths.md).

# Таблиці TeX: як TeX обчислює ширину об'єднаних стовпців

## Мета цієї статті

У цій статті ми досліджуємо, як $$\mathrm\TeX$$ обчислює ширини стовпців таблиці, коли таблиці містять елементи (наприклад, заголовки таблиць), що охоплюють кілька стовпців (наприклад, за допомогою $$\mathrm\TeX$$ примітивів `\omit` та `\span`). Використовуючи базову [«референсну» таблицю](#reference-table) як відправну точку, ми створюємо низку прикладів — похідних від цієї референсної таблиці — змінюючи різні елементи, щоб створити стовпці, які охоплюють кілька колонок. Розглядаючи вплив цих змін, ми можемо почати формувати розуміння базового алгоритму, який $$\mathrm\TeX$$ використовує для обчислення ширини стовпців, що охоплюють кілька колонок.

### Використання $$\mathrm\TeX$$ не $$\mathrm\LaTeX$$

Щоб розглянути й пояснити *як* $$\mathrm\TeX$$ визначає ширини стовпців, що охоплюють кілька колонок, необхідно відмовитися від усіх чудових $$\mathrm\LaTeX$$ пакетів для таблиць і повернутися до фундаментальних, низькорівневих (примітивних) команд створення таблиць: зокрема, `\halign{...}`, `\span` та `\omit`. [Існуючі $$\mathrm\TeX$$/$$\mathrm\LaTeX$$ пакети для таблиць](https://ctan.org/topic/table) є, звісно, важливими інструментами підвищення продуктивності й надають безліч надзвичайно корисних можливостей, які дають користувачам змогу швидко створювати величезну різноманітність табличного матеріалу за допомогою $$\mathrm\LaTeX$$. Ці пакети забезпечують необхідний «макрокаркас», побудований навколо $$\mathrm\TeX$$поведінки низького рівня, а їхні розробники надають дуже бажані абстракції й шари ізоляції, які беруть на себе турботу про базові складності. Багато з цих пакетів — це справді неймовірні досягнення складного $$\mathrm\TeX$$ програмування: усі ми маємо бути вдячні, що вони існують і захищають нас від необхідності використовувати сирий $$\mathrm\TeX$$!

Справжній алгоритм, який $$\mathrm\TeX$$ використовує для обчислення ширини стовпців, що охоплюють кілька колонок, пояснено на сторінці 245 [$$\mathrm\TeX\text{book}$$](https://www.amazon.co.uk/TeXbook-Donald-E-Knuth/dp/0201134489) і, з додатковими подробицями, у розділі 801 (стор. 336) друкованої книги, що містить $$\mathrm\TeX$$вихідний код [$$\mathrm\TeX\text{: The Program}$$](https://www.amazon.co.uk/Computers-Typesetting-Tex-Program-TEX/dp/0201134373). Однак для багатьох людей (включно зі мною) пояснення Кнута іноді доволі стислі й лаконічні, а подеколи їх важко простежити в деталях: ілюстровані приклади завжди дуже корисні.

### Так, таблиці складні

У розділі 768 (стор. 322) книги [$$\mathrm\TeX\text{: The Program}$$](https://www.amazon.co.uk/Computers-Typesetting-Tex-Program-TEX/dp/0201134373), Кнут робить цікаве зауваження:

> «Це трохи схоже на диво, коли `\halign` та `\valign` працюють, бо вони перетинають так багато структур керування $$\mathrm\TeX$$».

Крім того, том IV чотиритомної книжкової серії [$$\mathrm\TeX\text{ in Practice}$$](https://www.amazon.co.uk/Tex-Practice-Set-Stephan-Bechtolsheim/dp/038797296X/ref=sr_1_11?s=books\&ie=UTF8\&qid=1504256043\&sr=1-11\&keywords=TeX+in+Practice) присвячує не менше ніж 180 сторінок (сс. 199–379) створенню таблиць у $$\mathrm\TeX$$ через `\halign` та `\valign`.

Отже, безпечно зауважити, що $$\mathrm\TeX$$ таблиці справді «доволі хитрі».

### Охоплення стовпців: \omit, \span і \multispan

Як зазначалося, щоб дослідити $$\mathrm\TeX$$обчислення ширини стовпців нам потрібно використовувати «сирий» $$\mathrm\TeX$$; тобто комбінацію примітивних команд і одного $$\text{Plain }\mathrm\TeX$$ макросу під назвою `\multispan`. Хоча ми не будемо використовувати ці команди для безпосередньої ілюстрації наших прикладних таблиць (тобто повністю пояснювати весь $$\mathrm\TeX$$ код), варто коротко пояснити їх:

* `\halign`: Один із двох $$\mathrm\TeX$$ примітивів (команд) для створення таблиць. Інший — це `\valign` але він не настільки широко використовується і не буде розглядатися в цій статті.
* `\omit`: $$\mathrm\TeX$$ примітив (команда), що наказує $$\mathrm\TeX$$ ігнорувати шаблон преамбули елемента таблиці.
* `\span`: $$\mathrm\TeX$$ примітив (команда), що використовується для поєднання двох сусідніх елементів таблиці.
* `\multispan{n}`: Простий $$\mathrm\TeX$$ макрос для охоплення `n` стовпців.

По суті, щоб охопити стовпці, $$\mathrm\TeX$$ ігнорує відповідну кількість шаблонів преамбули таблиці та поєднує потрібну кількість елементів таблиці в один елемент. `\multispan{n}` працює шляхом розгортання в послідовність `\omit` та `\span` лексем, необхідних для охоплення `n` стовпців. Наприклад, `\multispan{3}` розгортається в `\omit\span\omit\span\omit`.

## Знайомство з нашою «референсною» таблицею

Ось наша референсна таблиця, а далі — анотована версія, яка пояснює елементи, використані в її побудові:

![{{{alt}}}](/files/83b6f6b26d9fab44cab9b8719e559a3498c8c16e)

Вносячи зміни до нашої референсної таблиці, ми спостерігатимемо, що відбувається з шириною таблиці та шириною окремих стовпців, коли ми додаємо елементи, що охоплюють різні стовпці. Цю референсну таблицю було створено в сирому $$\mathrm\TeX$$ за допомогою `\halign{...}` примітиву разом із низкою власних макросів, потрібних для верстки таблиць — ми не будемо обговорювати ці макроси, бо вони не є суттєвими для розуміння прикладів і пояснень.

Ось анотована версія нашої референсної таблиці, щоб пояснити її особливості:

![{{{alt}}}](/files/f844ecca631ed5b3ae87c1f469325f94a5f5cb46)

У нашому першому наборі прикладних таблиць і початковій референсній таблиці для всіх установлено `\tabskip=0pt` так, що $$\mathrm\TeX$$ не додає жодного проміжку між нашими стовпцями: фактично вони всі торкаються один одного. Причина цього — спростити початкове обговорення і подальші обчислення; пізніше в статті ми знову введемо ненульове `\tabskip` клейове заповнення, щоб дослідити його вплив на обчислення ширини стовпців, що охоплюють кілька колонок.

Як зазначено в примітках, ми додали невелику кількість вільного простору (5pt) на початку всіх ненакривних елементів таблиці (крім першого рядка). Ці 5pt вільного простору є частиною загальної ширини всіх ненакривних елементів (крім першого рядка) і були додані лише для того, щоб таблиця виглядала трохи менш захаращеною.

### Коротка примітка про ширину таблиць

Функція `\halign{...}` команда має три форми:

* `\halign{...}`: встановити ширину таблиці в ту ширину, $$\mathrm\TeX$$ яку обчислює, спираючись на розмір елементів (і `\tabskip` клейового заповнення);
* `\halign to *width* {...}`: наказує $$\mathrm\TeX$$ верстати таблицю до вказаної `*ширини*`;
* `\halign spread *amount*{...}`: скоригувати обчислену ширину на `*amount*`.

Коли $$\mathrm\TeX$$ верстає таблицю, використовуючи `\halign{...}` він має прочитати всю таблицю в пам’ять, щоб виконати різні обчислення, потрібні для її верстки. Отже, якщо ви не вказали ширину за допомогою `\halign to *width* {...}` ви не можете знати кінцеву ширину, доки $$\mathrm\TeX$$ не завершить її обробку (верстку). Один зі способів отримати ширину таблиці, створеної `\halign{...}` — спершу верстати таблицю всередині `\vbox{...}` (наприклад, `\setbox0=\vbox{\halign{...}}`) а потім, наприклад, використати `\the\wd0` щоб отримати ширину.

### Автоматичне перенесення рядків у елементах таблиці відсутнє

Важливо зазначити, що коли $$\mathrm\TeX$$ верстає таблицю, створену за допомогою `\halign{...}` будь-який текст у межах елементів таблиці не піддається автоматичному перенесенню рядків: елементи таблиці верстаються в *обмеженому горизонтальному режимі*— так само, як `\hbox`. Щоб увімкнути перенесення рядків, текст елемента таблиці потрібно помістити всередину `\vbox{...}` разом із використанням відповідного значення для `\hsize` всередині цього `\vbox{...}`. Однак зауважте, що текст у `\noalign{...}` команда (а $$\mathrm\TeX$$ примітив), що використовується в `\halign{...}` підлягає $$\mathrm\TeX$$перенесенню рядків, яке виконує `\noalign{...}` дає змогу $$\mathrm\TeX$$ «вийти» з `\halign{...}` і помістити матеріал між рядками таблиці — зазвичай для створення горизонтальних ліній між рядками таблиці.

### Не дозволено: \halign{...} всередині \hbox{...}

Ви не можете *безпосереднього* верстати `\halign{...}` всередині `\hbox{...}`. Спроба використати `\hbox{\halign{...}}` спричинить досить заплутану помилку:

```latex
! Missing } inserted.
<inserted text>
                }
<читати ще раз>
                   \halign
l.1 \hbox{\halign
```

#### Пояснення цієї помилки

Через зовнішній `\hbox{...}` $$\mathrm\TeX$$ перебуває в *обмеженому горизонтальному режимі*; тоді він виявляє `\halign{...}` який є *командою вертикального режиму. Наприклад, якщо ви використовуєте* у межах абзацу, `\halign{...}` завершить абзац, опрацює $$\mathrm\TeX$$ а потім продовжить решту абзацу. `\halign{...}` Коли використовується всередині

спонукає `\hbox{...}`, а `\halign{...}` спробувати повернутися до вертикального режиму, намагаючись примусово закрити поточну групу: $$\mathrm\TeX$$ виводить « $$\mathrm\TeX$$ ! Missing }`» і повідомляє про помилку, тому що вважає, що ви припустилися помилки у використанні групування. Хоча права дужка (`) може й не бракувати у вашому`}`коді, повідомлення про помилку є симптомом того, що $$\mathrm\TeX$$ «втручається» і `\hbox{...}` робить свій «найкращий здогад» щодо належного курсу дій для розв’язання проблеми. $$\mathrm\TeX$$ робить свій «найкращий здогад» щодо належного курсу дій для розв’язання проблеми.

## Приклади таблиць із охопленими стовпцями

Наведена нижче послідовність графічних зображень таблиць надає низку прикладів, щоб продемонструвати ефект охоплення стовпців таблиці: це показує, що довгі елементи таблиці можуть мати неочікувані наслідки для ширини певних стовпців — а отже, і для ширини самої таблиці. Питання, яке ми збираємося розглянути: що робить $$\mathrm\TeX$$ коли певний елемент таблиці охоплює кілька стовпців, але він «занадто широкий, щоб уміститися». Як зазначалося вище, $$\mathrm\TeX$$ справді застосовує до цієї проблеми обчислення ширин стовпців конкретний алгоритм: наведені далі приклади покликані допомогти сформувати «відчуття» роботи цього алгоритму.

### Приклад таблиці 1

У цьому прикладі ми використовуємо `\multispan{2}` щоб охопити стовпці 1 і 2 елементом, текст якого **Заголовок таблиці**:

![{{{alt}}}](/files/abf9b6a689f510f05c91361616bb29a0584278ab)

#### Спостереження

* Ширина цієї таблиці така сама, як у [референсної таблиці](#reference-table): $$327.71722\text{pt}$$.
* Ширина елемента, що охоплює стовпці 1 і 2, $$81.04953\text{pt}$$ є меншою за загальну ширину елементів у стовпцях, які він охоплює: $$52.56676\text{pt} + 57.06679\text{pt} = 109.63355\text{pt}$$

## Приклад таблиці 2

Як і в [Приклад таблиці 1](#example-table-1), у цьому прикладі також використовується `\multispan{2}` для охоплення стовпців 1 і 2, але тут ми використовуємо довший елемент, текст якого **Трохи довший заголовок таблиці**.

![{{{alt}}}](/files/2deedfe41455e1b722fb087d1b61ab2d56d37399)

#### Спостереження

Якщо порівняти цей приклад із нашим [референсної таблиці](#reference-table) ми можемо побачити таке:

* Ширина цієї таблиці збільшилася з $$327.71722\text{pt}$$ на $$374.37032\text{pt}$$: до загалом $$46.6531\text{pt}$$.
* Ширина елемента, що охоплює стовпці 1 і 2 ($$156.28664\text{pt}$$) є більшою за загальну ширину елементів у стовпцях, які він охоплює: $$52.56676\text{pt} + 57.06679\text{pt} = 109.63355\text{pt}$$. Ця різниця становить $$156.28664\text{pt}-109.63355\text{pt} = 46.6531\text{pt}$$ , тобто на ту саму величину, на яку збільшилася ширина таблиці.
* $$\mathrm\TeX$$ підлаштував ширину стовпця 2, щоб забезпечити додатковий простір, який потрібен. Пізніше ми побачимо, як $$\mathrm\TeX$$ обчислює величину, на яку стовпець 2 має збільшитися.
* Стовпець 1 не зазнав впливу: його ширина не була змінена елементом, що охоплює стовпці 1 і 2.

### Приклад таблиці 3

У цьому прикладі ми використовуємо `\multispan{3}` щоб охопити стовпці 1 до 3 елементом, текст якого такий самий, як у [Приклад таблиці 2](#example-table-2): **Трохи довший заголовок таблиці**.

![{{{alt}}}](/files/0562c3708a58eb280eab5c9bc3e3655b02fb66e3)

#### Спостереження

* Ширина цієї таблиці така сама, як у [референсної таблиці](#reference-table): $$327.71722\text{pt}$$.
* Ширина елемента, що охоплює стовпці 1 до 3 ($$156.28664\text{pt}$$) є меншою за загальну ширину елементів у трьох стовпцях, які він охоплює: $$52.56676\text{pt} + 57.06679\text{pt} + 59.03899\text{pt} = 168.67254\text{pt}$$.
* Жодна з ширин стовпців не була змінена елементом, що охоплює стовпці 1 до 3.

Чи починаєте ви бачити, як виникає закономірність?

### Приклад таблиці 4

Як і у [Приклад таблиці 3](#example-table-3), тут ми використовуємо `\multispan{3}` щоб охопити стовпці 1 до 3, але цього разу з елементом, текст якого значно довший: **Набагато довший заголовок таблиці, який простягається дуже далеко**.

![{{{alt}}}](/files/fc3663e8b769924ff0fc2f8de70f81c3038c8143)

#### Спостереження

* У порівнянні з [референсної таблиці](#reference-table), ширина цієї таблиці збільшилася з $$327.71722\text{pt}$$ на $$465.95685\text{pt}$$: на величину $$138.23963\text{pt}$$.
* Ширина елемента, що охоплює стовпці 1 до 3, $$306.91216\text{pt}$$.
* Загальна ширина елементів у трьох охоплених стовпцях становить $$52.56676\text{pt} + 57.06679\text{pt} + 59.03899\text{pt} = 168.67254\text{pt}$$.
* Різниця в ширині між довгим охоплювальним елементом і елементами у стовпцях 1 до 3 становить $$306.91216\text{pt}-168.67254\text{pt}=138.23962\text{pt}$$. Така сама величина (до 4 знаків після коми!), на яку збільшилася ширина таблиці.
* Лише ширина стовпця 3 була збільшена: ні стовпець 1, ні стовпець 2 не зазнали впливу.

#### Виникає закономірність

Якщо подивитися на [Приклад таблиці 2](#example-table-2) та [Приклад таблиці 4](#example-table-4) ми можемо побачити, що в обох випадках саме **останній стовпець у діапазоні** у якого ширину було збільшено, щоб звільнити місце для довгого елемента, що охоплював стовпці:

* У [Приклад таблиці 2](#example-table-2): Довгий елемент охоплював стовпці 1 і 2. Стовпець 2 став «розтягнутим».
* У [Приклад таблиці 4](#example-table-4): Довгий елемент охоплював стовпці 1 до 3. Стовпець 3 став «розтягнутим».

#### Ширина стовпця 3: Чи проступає алгоритм?

Наведені нижче обчислення дають чіткіше уявлення про те, що $$\mathrm\TeX$$ робить. Ось що ми знаємо:

* Ширина довгого елемента, що охоплює стовпці 1 до 3, $$306.91216\text{pt}$$.
* Загальна ширина елементів у стовпцях 1 і 2 становить $$52.56676\text{pt} + 57.06679\text{pt} = 109.63355\text{pt}$$.

Яка різниця між цими значеннями? Вона дорівнює $$306.91216\text{pt}-109.63355\text{pt} = 197.2786\text{pt}$$ і це ширина, використана для стовпця 3: вона безпосередньо випливає з алгоритму, який використовує $$\mathrm\TeX$$.

### Приклад таблиці 5

Перш ніж перейти до складнішого прикладу, ось ще один «простий» приклад. Ця таблиця містить той самий довгий елемент, що й у [Приклад таблиці 4](#example-table-4): **Набагато довший заголовок таблиці, який простягається дуже далеко**; однак цього разу ми використовуємо `\multispan{6}` що дає змогу цьому елементу охопити всю таблицю. Як бачите, отримана таблиця все ще має ту саму ширину, що й наша [референсної таблиці](#reference-table) ($$327.71722\text{pt}$$) тобто жоден стовпець не зазнав впливу цього дуже довгого елемента. Очевидно, це тому, що ширина елемента ($$306.91216\text{pt}$$) є меншою за загальну ширину всіх елементів, які він охоплює: $$327.71722\text{pt}$$; тобто ширину таблиці.

![{{{alt}}}](/files/7e85463c14e999f20c87d06e85a6c8dc5596ed42)

### Приклад таблиці 6: Трохи складніше

Тут ми розглядаємо серію з трьох прикладних таблиць (6(a)–6(c)), щоб показати вплив двох різних елементів, які обидва заходять у стовпець 5. [Приклад таблиці 6(a)](#example-table-6a) та [Приклад таблиці 6(b)](#example-table-6b) кожна показує таблицю, що містить один елемент, який охоплює кілька стовпців аж до стовпця 5. [Приклад таблиці 6(c)](#example-table-6c) об’єднує обидва охоплювальні елементи в одну таблицю й ставить питання: який саме елемент фактично визначає ширину стовпця 5, і чому? Відповідь веде нас до суті алгоритму, який використовує $$\mathrm\TeX$$.

#### Приклад таблиці 6(a)

![{{{alt}}}](/files/0162f48157493a80346bd82a3b3c32c354d1fffb)

**Спостереження**

* У порівнянні з [референсної таблиці](#reference-table), ширина цієї таблиці збільшилася з $$327.71722\text{pt}$$ на $$371.11153\text{pt}$$: на величину $$43.39431\text{pt}$$.
* Ширина елемента, що охоплює стовпці 3 до 5, $$215.06683\text{pt}$$.
* Загальна ширина елементів у стовпцях 3 до 5 становить $$59.03899\text{pt} + 52.98344\text{pt} + 59.6501\text{pt} = 171.67253\text{pt}$$.
* Різниця в ширині між елементами, охопленими в стовпцях 3 до 5, та шириною елемента, що охоплює, становить $$215.06683\text{pt}-171.67253\text{pt}=43.3943\text{pt}$$: точна величина (до 4 знаків після коми!), на яку збільшилася ширина таблиці.

#### Приклад таблиці 6(b)

![{{{alt}}}](/files/4b84ef7d62459284241bdf7849a89231d66d38e7)

**Спостереження**

* У порівнянні з [референсної таблиці](#reference-table), ширина цієї таблиці збільшилася з $$327.71722\text{pt}$$ на $$353.3233\text{pt}$$: на величину $$25.60608\text{pt}$$.
* Ширина елемента, що охоплює стовпці 1 до 5, $$306.91216\text{pt}$$.
* Загальна ширина елементів у стовпцях 1 до 5 становить $$52.56676\text{pt} + 57.06679\text{pt} + 59.03899\text{pt} + 52.98344\text{pt} + 59.6501\text{pt} = 281.30608\text{pt}$$.
* Різниця в ширині між елементами, охопленими в стовпцях 1 до 5, та шириною елемента, що охоплює, становить $$306.91216\text{pt}-281.30608\text{pt}=25.60608\text{pt}$$: **note** це *менше* ніж значення, обчислене для [Прикладу 6(a)](#example-table-6a), яке становило $$43.3943\text{pt}$$.

#### Приклад таблиці 6(c)

Тут ми поєднуємо елементи з прикладних таблиць [6(a)](#example-table-6a) та [6(b)](#example-table-6b) в одну таблицю: що відбувається?

![{{{alt}}}](/files/4364cf8a2c20d87fdc6c35375e8743dc2cce6626)

**Спостереження**

* У порівнянні з [референсної таблиці](#reference-table), ширина цієї таблиці збільшилася з $$327.71722\text{pt}$$ на $$371.11153\text{pt}$$: на величину $$43.39431\text{pt}$$. Ми зазначаємо, що це точно так само, як і в [Приклад таблиці 6(a)](#example-table-6a).

#### Що $$\mathrm\TeX$$ робить?

Щоб зрозуміти результати алгоритму та процесів ухвалення рішень $$\mathrm\TeX$$, ми зазначаємо, що цей елемент

![{{{alt}}}](/files/a77e39d01044bdb211d51e916b76fe06eea1af14)

виходить за межі елементів, які охоплюються $$25.60608\text{pt}$$; однак цей елемент

![{{{alt}}}](/files/0afd9374490f81d2d92fe8dc7732459f66a6e33f)

виходить ще далі за межі елементів, які охоплюються: на $$43.3943\text{pt}$$. Отже, саме цей елемент «виграє перегони», і ширина стовпця 5 збільшується на **максимум** з цих двох значень ($$43.3943\text{pt}$$). Тепер ширина стовпця 5 стає $$59.6501\text{pt} + 43.3943\text{pt} = 103.0444\text{pt}$$ щоб умістити елемент, який охоплює стовпці 3 до 5. Наш опис точної «послідовності подій» трохи спрощений, але результат такий, як ми описали.

## Повертаючись до певної складності

Щоб мінімізувати складність наших обговорень (досі) ми використовували відносно прості приклади для демонстрації принципів $$\mathrm\TeX$$алгоритму; зокрема, ми встановили `\tabskip=0pt`. На практиці таблиці «реального світу» ймовірно матимуть багато елементів, що охоплюють діапазон стовпців, і, звісно, матимуть ненульові значення для `\tabskip` клейового заповнення — тему, до якої ми зараз повернемося.

### \tabskip glue та ширини стовпців, що охоплюються

Проєктування таблиці часто вимагає додавання вільного простору між стовпцями і, звісно, $$\mathrm\TeX$$ має для цього засіб у вигляді примітивної команди під назвою `\tabskip`. Цю команду можна використовувати, щоб розмістити фіксоване або гнучке клейове заповнення (проміжок):

* перед таблицею (тобто ліворуч від стовпця 1);
* між одним або кількома стовпцями;
* після таблиці (тобто праворуч від останнього стовпця).

Ось приклад, щоб нагадати собі:

![{{{alt}}}](/files/0af1a883d948685fd67c3ac78022d796e56d3c8d)

### Як клейове заповнення \tabskip впливає на ширину стовпців, що охоплюються?

Наявність ненульового `\tabskip` клейового заповнення між стовпцями надає додатковий простір, який елементи, що охоплюють, можуть «поглинути» перед $$\mathrm\TeX$$ має подумати про збільшення ширини останнього стовпця в діапазоні.

У нашому наступному прикладі ми використаємо дві таблиці, щоб порівняти результати охоплення двох стовпців. Єдина різниця між таблицями — використання `\tabskip` клейового заповнення.

* Перший приклад використовує нашу оригінальну «референсну» таблицю, яка, якщо пам’ятаєте, має встановлено `\tabskip=0pt`.
* Другий приклад використовує модифіковану версію нашої [референсної таблиці](#reference-table) (з анотацією вище), яка має `\tabskip=10pt` перед і після таблиці, але, що важливіше, вона має встановлено `\tabskip=20pt` між стовпцями.

У *модифікованій* референсній таблиці два охоплювані стовпці не впливають на ширини стовпців (і ширину таблиці), але вони впливають на ширину стовпця 2 (і ширину таблиці) в *оригінальній* [референсної таблиці](#reference-table).

### Оригінальна референсна таблиця: \tabskip=0pt

Тут ми показуємо нашу оригінальну [референсної таблиці](#reference-table) разом із другою таблицею (похідною від нашої оригінальної [референсної таблиці](#reference-table)) яка має елемент «**Перевірити довший заголовок таблиці**» що охоплює стовпці 1 і 2. Цілком очевидно, що стовпець 2 (у другій таблиці на діаграмі), а отже й уся таблиця, обидва зазнають впливу охоплених стовпців.

![{{{alt}}}](/files/a68b53cd6fd8ec3d8353f5be6e590cd40c103807)

### Модифікована референсна таблиця: \tabskip=20pt

Тут ми показуємо нашу модифіковану референсну таблицю разом із другою таблицею (похідною від нашої модифікованої референсної таблиці), яка також має елемент «**Перевірити довший заголовок таблиці**» що охоплює стовпці 1 і 2. Цілком очевидно, що в другій таблиці на діаграмі ні ширина стовпця 2, ні ширина таблиці не зазнають впливу охоплених стовпців. У цьому випадку наявність `\tabskip` клейового заповнення (`20pt`) між стовпцями допомогла «поглинути» простір, потрібний для тексту в елементі, що охоплює стовпці 1 і 2:

![{{{alt}}}](/files/31e22e32d959d89db4c7d93f2beb1c9cd252af6c)

## Суть $$\mathrm\TeX$$алгоритму

Сподіваємося, наведений вище набір прикладів допоміг сформувати «відчуття» того, що $$\mathrm\TeX$$ робить, щоб умістити елементи, які охоплюють кілька стовпців, і як $$\mathrm\TeX$$ за потреби, регулюватиме ширину **останнього** стовпця в кожному діапазоні охоплених стовпців. Окрім ширини елементів у окремих стовпцях, які охоплюються, наявність ненульового `\tabskip` клейового заповнення є важливим чинником, який $$\mathrm\TeX$$ бере до уваги, вирішуючи, чи потрібно йому коригувати будь-яку ширину стовпців. Головне, що слід пам’ятати, це те, що $$\mathrm\TeX$$мета — обчислити придатну ширину для **останній стовпець** у межах кожного діапазону охоплених стовпців.

### Остаточний приклад таблиці: останні стовпці в діапазоні, що охоплюється

У цьому завершальному прикладі ми знову використовуємо нашу змінену опорну таблицю (з `\tabskip` значеннями glue, про які йшлося вище) щоб отримати ще одну таблицю, яка містить різні стовпці, охоплені лініями — ми використали лінії, щоб полегшити візуальне сприйняття охоплень.

Дві таблиці було ретельно вирівняно, щоб показати, що у верхній таблиці жодні стовпці перед стовпцем 5 не зазнали впливу від охоплених стовпців. Темно-зелена ділянка ліворуч від діаграми показує, що стовпці 1–4 в обох таблицях і далі точно збігаються. Праворуч є світліша зафарбована зелена ділянка, яка показує, що лише стовпці 5 і 6 зазнали впливу від записів, що охоплюють кілька стовпців.

Верхня таблиця має такі охоплення:

* стовпці 1–5: охоплені $$400\text{pt}$$ лінією;
* стовпці 3–5: охоплені $$200\text{pt}$$ лінією;
* стовпці 4–6: охоплені $$250\text{pt}$$ лінією.

![{{{alt}}}](/files/54527d2fb87b546f8512f1d742438e555d7fc97e)

Ще раз, пояснення полягає в тому, що в серії охоплених стовпців коригується лише ширина останнього стовпця (за потреби): проміжні стовпці не зазнають впливу, і тут це означає стовпці 1–4 — хоча, звісно, ширина стовпців 1–4 (та проміжних `\tabskip` glue) враховується під час обчислення скоригованої ширини стовпців 5 і 6.

### Покроковий розбір $$\mathrm\TeX$$алгоритму

Ми завершимо *спрощеним* покроковим розбором «$$\mathrm\TeX$$процесу міркувань» під час обчислення ширини стовпців у записах, що охоплюють кілька стовпців. Опис $$\mathrm\TeX$$алгоритмів не завжди простий, тож ми вдамося до певної «спрощувальної художньої вільності», щоб дати огляд того, що відбувається. Читачів, які цікавляться всіма заплутаними деталями, відсилаємо до розділу 801 (сторінка 336) друкованої книги, що містить $$\mathrm\TeX$$вихідний код [$$\mathrm\TeX\text{: The Program}$$](https://www.amazon.co.uk/Computers-Typesetting-Tex-Program-TEX/dp/0201134373).

Таблиці з реального світу часто створюють із численними використаннями `\span` примітива (наприклад, усередині $$\mathrm\LaTeX$$ пакетів) для створення кількох екземплярів охоплених стовпців у межах таблиці. Щоб керувати цим, структури даних (глибоко всередині $$\mathrm\TeX$$) зберігають інформацію (так звані *вузли охоплення*), які повідомляють $$\mathrm\TeX$$ про зв’язки (охоплення) між елементами/стовпцями таблиці. Очевидно, $$\mathrm\TeX$$ має застосовувати свої алгоритми систематично й повинен обробити всю таблицю, щоб виконати остаточні обчислення — визначити всі ширини стовпців, загальну ширину таблиці та, за потреби, величину, на яку мають розтягнутися або стиснутися гнучкі glue, використані в таблиці. Тож не дивно, що $$\mathrm\TeX$$ не може сказати вам остаточну ширину таблиці, доки повністю не обробить `\halign{...}` команду — у нього справді дуже багато роботи!

Відправною точкою для обчислення ширини стовпців є стовпець 1, тому що, звісно, ніщо не може охоплювати зліва від (і *через/у*) стовпець 1. $$\mathrm\TeX$$ спочатку визначає ширину стовпця 1, з’ясовуючи, який елемент має максимальну *природну ширину*. Назвемо цю максимальну ширину $$w\_1$$а якщо є елементи, що охоплюють стовпці 1 і 2, назвемо ширину такого елемента $$w\_{12}$$ (ширина від 1 до 2). Крім того, позначимо `\tabskip` glue між стовпцями 1 і 2 як $$t\_{1}$$—зверніть увагу, що ми розглядаємо лише *природну ширину* тільки `\tabskip` цього glue і наразі ігноруємо будь-які компоненти розтягування чи стиснення, які він може мати. Також нехай максимальна природна ширина всіх елементів у стовпці 2, що не охоплюють кілька стовпців, буде $$w\_2$$.

Ключовий момент полягає в тому, що $$\mathrm\TeX$$ намагається обчислити ширину стовпця 2, розглядаючи лише ті елементи, де охоплення *починається* зі стовпця 1 і *закінчується* на стовпці 2. Ключовим міркуванням для $$\mathrm\TeX$$ є перевірка $$\max(w\_{2}, w\_{12} - (w\_1+ t\_1))$$—може бути кілька елементів, що охоплюють стовпці 1 і 2: деякі можуть бути вузькими (малий $$w\_{12}$$), інші — дуже широкими (великий $$w\_{12}$$) тож $$\mathrm\TeX$$ шукає той, що має найбільший ефект (звідси $$\max(\text{...})$$). Тут значення $$w\_{12} -(w\_1+ t\_1)$$ —це величина, на яку елемент, що охоплює стовпці 1 і 2, «виходить за межі» стовпця 1 у стовпець 2: зауважте, що $$\mathrm\TeX$$ використовує ширину стовпця 1 **та** сайті `\tabskip` клейового заповнення ($$t\_{1}$$) між стовпцями 1 і 2. Після того як $$\mathrm\TeX$$ визначить, чи впливають якісь охоплення від стовпця 1 до 2 на ширину стовпця 2, він установлює ширину стовпця 2 на максимальне значення, яке він визначив (використовуючи описану перевірку). $$\mathrm\TeX$$ продовжує проходити всі інші стовпці, виконуючи подібні перевірки.

І нарешті, для повноти, наведемо суть $$\mathrm\TeX$$алгоритму обчислення ширини стовпців (взяту з документації до вихідного коду Кнута для $$\mathrm\TeX$$):

Нехай $$w\_{ij}$$ буде максимумом природних ширин усіх елементів, що охоплюють стовпці $$i$$ через $$j$$, включно. Остаточні ширини стовпців визначаються формулою

$$\begin{equation\*} w\_j=\max\_{1\leq i\leq j}\biggl(w\_{ij}-\sum\_{i\leq k< j}(t\_k+w\_k)\biggr) \end{equation\*}$$

де $$t\_k$$ —це природна ширина glue tabskip між стовпцями $$k$$ та $$k+1$$.

## Колофон: використання Overleaf для створення таблиць як графіки SVG

Усі $$\mathrm\TeX$$ таблиці, представлені в цій статті, є файлами Scalable Vector Graphics (SVG), створеними на платформі Overleaf. Позначки (стрілки та зелені прямокутники) було додано шляхом відкриття SVG-графіки в Inkscape — зауважте, однак, що текст позначок було набрано в $$\mathrm\TeX$$ як додатковий текст, що супроводжує таблицю: в Inkscape було додано лише стрілки та зелені фони. Якщо вам цікаво, як цього було досягнуто, читайте далі.

Сервери Overleaf використовують $$\mathrm\TeX \text{ Live}$$ дистрибутив, який, окрім $$\mathrm\TeX$$систем верстання на основі, надає безліч дуже корисних $$\mathrm\TeX$$-пов’язаних програмних інструментів і утиліт. Серед них є одна під назвою [`dvisvgm`](https://dvisvgm.de) яка, як підказує назва, перетворює $$\mathrm\TeX$$традиційний DVI (**D**e**V**ice **I**незалежний) формат вихідного файла у SVG. Серед його численних [параметрів командного рядка](https://dvisvgm.de/Manpage/) `dvisvgm` містить параметр (`-n` або `--no-fonts`) який наказує йому перетворювати весь текст у *контури* що означає, що текст у SVG-графіці малюється за допомогою ліній і кривих, а не справжніх шрифтів і гліфів. Це може збільшити розмір файлу отриманої SVG-графіки, але гарантує, що SVG-графіка є надзвичайно портативною і майже напевно добре працюватиме на будь-якому пристрої.

### То... як це було зроблено?

У [попередній статті](https://www.overleaf.com/blog/510-using-luatex-to-run-tools-and-utilities-installed-on-overleafs-servers) я розповідав, як можна використовувати $$\text{Lua}\mathrm\TeX$$ для запуску різноманітних програмних інструментів і утиліт, установлених на серверах Overleaf, — це надзвичайно простий і зручний спосіб. Цей спосіб було використано для створення SVG-графіки набраних $$\mathrm\TeX$$ таблиць, ось як. Із головного $$\mathrm\TeX$$ файла документа код для набору кожної таблиці (створений за допомогою using `\halign`) було записано у `.tex` файл. Це було досягнуто шляхом укладання коду таблиці в пару команд, які я назвав `\beginscoop` та `\endscoop`. Ймовірно, є багато інших способів досягти потрібного результату, але ось визначення макросів, які я використовував:

```latex
\def\cc{\catcode`\#=12\relax}
\long\def\scoop#1\endscoop{\global\fulltoks={#1}\egroup}
\def\beginscoop{\global\advance\numfigs by1\relax\bgroup\cc\scoop}
```

Ви використовуєте їх так:

```latex
\beginscoop
\halign{...}
\endscoop
```

Зауважте, що `\endscoop` токен лише слугує для позначення меж параметра `\scoop` макроса: $$\mathrm\TeX$$ фактично відкидає `\endscoop` токен, тож нам насправді не потрібно його визначати (наприклад, через `\def\endscoop{...}`).

Функція $$\mathrm\TeX$$ код, що міститься у `\halign{...}` зберігається у `toks` реєстрі з назвою `\fulltoks`. Одна складність, з якою я зіткнувся (з $$\text{Lua}\mathrm\TeX$$) полягала в тому, щоб запобігти `#` символам у `\halign{...}` преамбулі від «подвоєння» до `##` під час запису у `.tex` файл. Щоб уникнути цього, мені довелося тимчасово встановити `\catcode`значення `#` кодові значення символів на 12 перед збереженням $$\mathrm\TeX$$ коду (токенів) у `\fulltoks` реєстрі токенів.

Наступний крок — записати токени, що містяться в `\fulltoks` як $$\mathrm\TeX$$ файл — оскільки я використовував $$\text{Lua}\mathrm\TeX$$ це виявилося *надзвичайно* легко завдяки $$\text{Lua}\mathrm\TeX$$чудовому Lua API. Коротко кажучи, я написав макрос під назвою `\writefile{...}` який як параметр приймає ім’я реєстру токенів, токени якого ви хочете записати у файл (наприклад, `\writefile{fulltoks}`). Усередині `\writefile{...}` макроса я використав Lua API, щоб отримати текстове представлення `\fulltoks` реєстру токенів:

```latex
\def\writefile#1{%
\directlua{
...
...
 local p=tex.toks["#1"]
...
...
}}
```

Ось знімок екрана, який показує трохи більше `\writefile{...}` команди:

[![{{{alt}}}](/files/11e6bbe5e5e621b9498fbbb21ccc0409b788bd85)](https://www.filepicker.io/api/file/ngeDmgRStGWvG044RE1A)

Мова Lua та Lua API, наданий $$\text{Lua}\mathrm\TeX$$ часто можуть спростити $$\mathrm\TeX$$ програмні завдання, і саме завдяки цим корисним і потужним можливостям я використовую $$\text{Lua}\mathrm\TeX$$ їх ще з \~2009 року — і досі залишаюся великим шанувальником цього справді чудового $$\mathrm\TeX$$ рушія. Гаразд, рекламна $$\text{Lua}\mathrm\TeX$$ рекламна вставка на цьому завершується.

Так легко отримавши $$\mathrm\TeX$$ код, збережений у `\fulltoks` його записують у файл разом із деяким додатковим кодом, щоб перетворити його на правильно сформований $$\mathrm\LaTeX$$ файл. Наступні кроки такі:

1. Обробіть `.tex` файл, що містить нашу таблицю, за допомогою $$\text{pdf}\mathrm\LaTeX$$ (у режимі DVI), щоб він набрав таблицю та згенерував `.dvi` файл для `dvisvgm` обробки. Так, ви можете використати $$\text{Lua}\mathrm\TeX$$ для запуску $$\text{pdf}\mathrm\LaTeX$$—і знову я використав метод, описаний у [попередній статті](/latex/uk/dokladni-statti/52-using-luatex-to-run-tools-and-utilities-installed-on-overleaf-s-servers.md).
2. І нарешті, запустіть `dvisvgm` щоб обробити `.dvi` файл, щоб згенерувати SVG-графіку набраної $$\mathrm\TeX$$ таблиці.
3. Щоб отримати самі SVG-графіки, ви можете завантажити ZIP-файл з Overleaf — не забудьте вибрати **Input and Output Files** опції.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/uk/dokladni-statti/47-tex-tables-how-tex-calculates-spanned-column-widths.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
