---
url: /templates/advanced/functions.md
description: >-
Все функции шаблонного движка Astral Moderation — логические, математика,
строки, списки, дата и время, кнопки, разметка и медиа — с примерами.
---
# Функции
Функция принимает значения и возвращает результат: upper('привет') → ПРИВЕТ. Функцию можно вызвать обычно — round(x) — или через pipe — x | round.
Новые функции отмечены значком .
## Логические { #logic }
| Функция | Возвращает `true`, когда |
|---|---|
| `defined(x)` | `x` определено (не `Undefined`) |
| `empty(x)` | `x` пусто: `null`, `Undefined`, `''`, пустой список или карта, `0` |
| `even(n)`, `odd(n)` | `n` четное, нечетное |
| `iterable(x)` | `x` — список, карта или страница индекса |
| `number(x)` | `x` — число или текст, похожий на число |
Эти же функции работают как [тесты](./expressions#tests): `x is empty`, `x is number`.
## Математика { #math }
| Функция | Что делает | Пример → результат |
|---|---|---|
| `abs(n)` | Модуль числа | `abs(-5)` → `5` |
| `round(n, режим?)` | Округление. Режим `'CEIL'` — вверх, `'FLOOR'` — вниз, без режима — до ближайшего | `round(1.3, 'CEIL')` → `2` |
| `min(…)`, `max(…)` | Наименьшее или наибольшее из аргументов или из списка | `max([3, 9, 4])` → `9` |
| `random(…)` | Случайное значение — см. ниже | |
### random { #random }
| Запись | Результат |
|---|---|
| `random(10)` | Случайное целое от 0 до 10 включительно |
| `random(1, 6)` | Случайное целое от 1 до 6 включительно |
| `random(['раз', 'два', 'три'])` | Случайный элемент списка |
| `random(['раз', 'два', 'три'], [10, 50, 40])` | Элемент с весами: 10%, 50% и 40% |
Если вес не указан или некорректен, он считается нулем — элемент не выпадет. Если некорректны все веса, элементы равновероятны.
```template
🎱 {{ random(['Да', 'Нет', 'Возможно', 'Спроси позже']) }}
```
## Строки { #strings }
| Функция | Что делает | Пример → результат |
|---|---|---|
| `lower(s)` | В нижний регистр | `lower('ПРИВЕТ')` → `привет` |
| `upper(s)` | В верхний регистр | `upper('abcd12')` → `ABCD12` |
| `capitalize(s)` | Первая буква заглавная | `capitalize('привет мир')` → `Привет мир` |
| `title(s)` | Каждое слово с заглавной | `title('клуб astral')` → `Клуб Astral` |
| `trim(s)` | Убрать пробелы по краям | `trim(' да ')` → `да` |
| `truncate(s, длина, окончание?)` | Обрезать слишком длинный текст и поставить в конце `…` (или свое окончание) | `truncate(member.name, 12)` → имя не длиннее 12 символов |
| `split(s, разделитель)` | Разбить на список | `split('a,b,c', ',')` → `[a, b, c]` |
| `startsWith(s, начало, безРегистра?)` | Начинается ли с | `startsWith('#TAG', '#')` → `true` |
| `endsWith(s, конец, безРегистра?)` | Заканчивается ли на | |
| `contains(s, что, безРегистра?)` | Есть ли подстрока. `что` может быть списком — тогда хотя бы одна из | `contains('Hey there!', ['there', 'heh'])` → `true` |
| `replace(s, карта, безРегистра?)` | Заменить все ключи карты на значения | `replace('Привет, %n%', { '%n%': 'Анна' })` → `Привет, Анна` |
| `replace(s, что, на_что)` | Заменить все вхождения строки | `replace('#AB12', '#', '')` → `AB12` |
| `format(шаблон, …)` | Подставить значения: `%s` — строка, `%d` — целое, `%f`, `%.2f` — дробное, `%%` — знак процента | `format('%s: %.1f%%', 'Побед', 62.54)` → `Побед: 62.5%` |
| `concat(…)`, `concatenate(…)` | Склеить строки | `concat('1', '+', '1')` → `1+1` |
| `escape_html(s)` | Заменить `& < > "` на HTML-сущности | |
| `url_encode(s)` | Закодировать для ссылки | `url_encode('клуб astral')` → `%D0%BA…` |
### number\_format { #number\_format }
`number_format(число, знаков?, разделитель_дроби?, разделитель_тысяч?)` — красивое число.
| Запись | Результат |
|---|---|
| `number_format(12480)` | `12 480` (по языку чата: для русского — пробел и запятая) |
| `number_format(11000.136, 2)` | `11 000,14` |
| `number_format(11000.136, 2, '.', ' ')` | `11 000.14` |
### plural { #plural }
`plural(число, язык, …формы)` выбирает правильную форму слова.
Для русского — четыре формы: для 1 (1 день), для 2–4 (2 дня), для 0 и 5–20 (5 дней) и для дробных (1,5 дня):
```template
{{ n }} {{ plural(n, 'ru', 'участник', 'участника', 'участников', 'участника') }}
```
Для английского — две формы: `plural(n, 'en', 'day', 'days')`.
## Списки и смешанные { #collections }
| Функция | Что делает | Пример → результат |
|---|---|---|
| `length(x)` | Длина списка, карты или строки. Для `null` — 0 | `length([1, 2])` → `2` |
| `first(x)`, `last(x)` | Первый или последний элемент (символ строки) | `first([5, 6])` → `5` |
| `reverse(x)` | Развернуть список или строку | `reverse('abc')` → `cba` |
| `default(x, запасное)` | `запасное`, если `x` — `null` или `Undefined` | `default(null, 0)` → `0` |
| `join(список, разделитель?)` | Склеить в строку, `null` пропускаются. По умолчанию разделитель `, ` | `join([1, null, 2], ' / ')` → `1 / 2` |
| `slice(x, начало, длина)` | Кусок списка или строки. Начало — с 0. Безопасна к выходу за границы | `slice([1, 2, 3], 0, 2)` → `[1, 2]` |
| `batch(список, размер)` | Разбить на группы | `batch([1, 2, 3], 2)` → `[[1, 2], [3]]` |
| `keys(x)`, `values(x)` | Ключи или значения карты (у списка ключи — номера) | `keys(['A', 'B'])` → `[0, 1]` |
| `sort(список, режим?)` | Сортировка: `ASC`, `DESC` — как строки, `NUM_ASC`, `NUM_DESC` — как числа (не-числа отбрасываются) | `sort(['2', '1', '10'], 'NUM_ASC')` → `[1, 2, 10]` |
| `sort_by(список, свойство, режим?)` | Сортировка объектов или карт по свойству | `club.members \| sort_by('trophies', 'DESC')` |
| `shuffle(список)` | Перемешать | |
| `unique(список)` | Убрать повторы | `unique([1, 1, 2])` → `[1, 2]` |
| `typeof(x)` | Название типа | `typeof(9)` → `Number` |
::: warning `sort` сравнивает как строки
`sort(['2', '1', '10'])` даст `[1, 10, 2]` — строки сравниваются посимвольно. Для чисел используйте `NUM_ASC` или `NUM_DESC`.
:::
## Дата и время { #datetime-functions }
| Функция | Что делает |
|---|---|
| `now()` | Текущий момент (DateTime) в часовом поясе чата |
| `calendar(значение?, пояс?)` | Создать DateTime из `'now'`, Unix-времени в миллисекундах или строки ISO 8601 |
| `date(значение, формат?, пояс?)` | Дата текстом в нужном формате — см. ниже |
| `datetime(значение, формат?)` | Дата, которую каждый увидит в своем поясе и на своем языке — см. ниже |
| `duration(мс, единиц?)` | Длительность текстом: `duration(3650)` → `3 сек. 650 мс` |
| `parse_duration(текст)` | Текст в миллисекунды: `parse_duration('1ч30м')` → `5400000` |
Методы дат (`plusDays`, `isBefore`…) — в справочнике [DateTime](/reference/datetime).
### date { #date }
`date(значение, формат, пояс)` форматирует дату. Значение — DateTime, Unix-время в миллисекундах или `'now'`. Пояс по умолчанию — часовой пояс чата из раздела **«Общие»**.
```template
{{ date('now', 'EEE, d MMM yyyy HH:mm:ss z', 'Europe/Moscow') }}
```
Результат: `сб, 11 апр. 2026 15:27:38 MSK`.
| Буквы | Что это | Пример |
|---|---|---|
| `yyyy`, `yy` | Год | `2026`, `26` |
| `MM`, `M` | Месяц числом | `04`, `4` |
| `MMM` | Месяц кратко | `апр.` |
| `MMMM` | Месяц полностью, в родительном падеже | `апреля` |
| `LLLL` | Месяц полностью, в именительном падеже | `апрель` |
| `dd`, `d` | День месяца | `09`, `9` |
| `EEE`, `EEEE` | День недели кратко и полностью | `сб`, `суббота` |
| `HH`, `H` | Часы (0–23) | `05`, `5` |
| `hh`, `h`, `a` | Часы (1–12) и AM/PM | |
| `mm` | Минуты | `07` |
| `ss` | Секунды | `38` |
| `SSS` | Миллисекунды | `042` |
| `z`, `Z`, `X` | Часовой пояс | `MSK`, `+0300` |
| `D`, `w`, `u` | День года, неделя года, день недели числом | |
Текст внутри формата берется в одинарные кавычки: `date(now(), "d MMMM 'в' HH:mm")` → `11 апреля в 15:27`.
### datetime { #datetime }
`datetime(значение, формат)` выводит дату специальной разметкой Telegram: каждый участник увидит ее **в своем часовом поясе и на своем языке**. Удобно для анонсов турниров, когда в чате люди из разных стран.
| Формат | Что покажет |
|---|---|
| `''` | Дату как есть, по нажатию — в поясе зрителя |
| `'r'` | Относительно: «через 2 часа», «вчера» |
| `'d'`, `'D'` | Дату кратко и полностью |
| `'t'`, `'T'` | Время кратко и полностью |
| `'w'` | День недели |
Буквы можно сочетать: `'wDT'` — день недели, полная дата и время.
```template
Турнир начнется {{ datetime(calendar('2026-10-03T15:00:00Z'), 'wDt') }} — это {{ datetime(calendar('2026-10-03T15:00:00Z'), 'r') }}.
```
## Кнопки и взаимодействия { #interactions }
| Функция | Что делает |
|---|---|
| `button(стиль, id_или_ссылка, надпись, эмодзи?, действие?, неактивная?)` | Кнопка под сообщением — подробно в статье [Кнопки и меню выбора](/commands/components#button) |
| `url_button(надпись, ссылка)` | Кнопка-ссылка. То же, что `button('LINK', ссылка, надпись)` |
| `copy_button(надпись, текст)` | Кнопка «скопировать текст» |
| `row()`, `components_row()` | Начать новый ряд кнопок |
| `button_row(кнопки, выравнивание?)` | Ряд из 1–8 кнопок внутри rich-сообщения |
| `inline_button(…)` | Кнопка прямо в строке rich-текста. Аргументы — как у `button` |
| `select_menu(тип, id, подсказка, действие, неактивное?)` | Меню выбора — см. [Кнопки и меню](/commands/components#select-menu) |
| `reaction(эмодзи)` | Реакция бота на свое сообщение. Одна на сообщение, эмодзи — из разрешенных Telegram |
Кнопки с действиями и меню работают только в [пользовательских командах](/commands/).
## Разметка { #markup }
Функции разметки возвращают **готовую безопасную разметку**: движок не экранирует ее повторно, а текст внутри экранирует сам. Поэтому ими удобно оформлять данные — `bold(member.name)` не сломается, даже если в имени есть звездочки. Все функции работают и в Markdown, и в HTML.
### Строчные { #inline }
| Функция | Результат |
|---|---|
| `bold(t)`, `italic(t)`, `underline(t)`, `strike(t)` | Жирный, курсив, подчеркнутый, зачеркнутый |
| `spoiler(t)` | Спойлер |
| `mark(t)` | Маркер (выделение) |
| `sup(t)`, `sub(t)` | Верхний и нижний индекс |
| `code(t)` | Моноширинный текст |
| `link(текст, ссылка)` | Ссылка |
| `mention(участник_или_id, текст?)` | Упоминание |
| `custom_emoji(id, запасной)` | Кастомный эмодзи. Работает, если у владельца бота Telegram Premium, иначе выводится запасной |
| `math(выражение)` | Формула в строке |
### Блоки { #blocks }
| Функция | Результат |
|---|---|
| `heading(текст, размер)` | Заголовок размера 1–6 |
| `quote(текст, автор?, раскрывающаяся?)` | Цитата; `true` третьим аргументом — раскрывается по нажатию |
| `pullquote(текст, автор?)` | Цитата-выноска |
| `details(заголовок, содержимое, открыт?)` | Сворачиваемый блок |
| `divider()` | Горизонтальная линия |
| `footer(текст)` | Подвал — мелкая строка внизу |
| `list(элементы, вид?)` | Список. `'ordered'` — нумерованный |
| `checklist(элементы)` | Чек-лист |
| `pre(текст, язык?)` | Блок кода |
| `math_block(выражение)` | Формула отдельным блоком |
| `anchor(имя)` | Якорь для ссылки внутри сообщения |
Все блочные функции новые . В режиме Text блоки [упрощаются](./rich#text-mode), а редактор предупреждает об этом.
### table { #table }
`table(строки, настройки?)` строит таблицу из списка списков. Значения ячеек экранируются, поэтому таблица не сломается, какими бы ни были данные.
```template
{{ table([
['Игрок', 'Кубки'],
['Анна', 24510],
['Иван', 19870]
], { header: true, striped: true }) }}
```
| Настройка | Что делает |
|---|---|
| `header` | Первая строка — заголовки столбцов |
| `bordered` | Рамки у ячеек |
| `striped` | Полосы через строку |
| `compact` | Компактные строки |
| `caption` | Подпись под таблицей |
| `index` | Добавить первый столбец с номером строки; значение — его заголовок, например `'#'` |
`table_of(объекты, столбцы, настройки?)` строит таблицу из списка объектов: `столбцы` — карта «свойство → заголовок».
```template
{{ table_of(club.members | sort_by('trophies', 'DESC') | slice(0, 10),
{ name: 'Игрок', trophies: 'Кубки' },
{ header: true, index: '#' }) }}
```
В таблице — до 20 столбцов. В режиме Text таблица станет моноширинным текстом.
### Медиа { #media }
| Функция | Что вставляет |
|---|---|
| `photo(ссылка, подпись?, спойлер?)` | Фото. `true` третьим аргументом — скрыть под спойлер |
| `video(…)`, `animation(…)` | Видео, GIF — аргументы как у `photo` |
| `audio(…)`, `voice(…)` | Аудио, голосовое сообщение |
| `document(ссылка, подпись?)` | Файл |
| `collage(медиа, подпись?)` | Коллаж из нескольких медиа |
| `slideshow(медиа, подпись?)` | Слайдшоу |
| `map(широта, долгота, масштаб?, подпись?)` | Карта с точкой |
Ссылки на медиа — только `https://`. Все медиафункции новые , подробнее — [Rich-сообщения](./rich#media).
## Данные Astral { #astral }
Клубы, игроки, рейтинги и черный список доступны не функциями, а через объект `astral`: `astral.club('#TAG')`, `astral.player('#TAG')`. См. [Пространство astral](../astral).