Ведущие нули в Int в Swift: от хаоса к порядку

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

«Пропавшие» нули: почему Int не хранит лидирующие нули и как с этим жить?

Вы когда-нибудь пытались вывести на экран число 007 и получали просто 7? Знакомая боль? Добро пожаловать в клуб разработчиков на Swift, которые рано или поздно сталкиваются с вопросом: «Как добавить ведущие нули к Int?».

Этот вопрос на Stack Overflow набрал тысячи просмотров, и неудивительно. Казалось бы, простая задача — отобразить номер заказа как «001234», а не «1234», или показать время как «09:05», а не «9:5». Но Swift, будучи строго типизированным языком, разделяет понятие «число» и «его строковое представление». Int — это математическая сущность. 007 для него — просто 7. Ведущие нули теряются при инициализации.

В этой статье мы разберём все основные подходы к решению этой проблемы. Вы узнаете, как правильно форматировать целые числа, какой способ выбрать для разных задач и как не попасть в ловушку производительности. Мы пройдём путь от простых строковых масок до мощного NumberFormatter из Foundation. Поехали!

Почему Int не может хранить «001»? Краткий ликбез

Прежде чем нырять в код, давайте разберёмся с природой явления. Int в Swift — это 64-битное (или 32-битное на старых устройствах) целое число со знаком. Его внутреннее представление — двоичный код. Ноль слева не имеет математического смысла.

let number = 007 // Ошибка? Нет!
print(number) // Выведет: 7

Компилятор Swift даже не даст вам написать 007 в коде (если только это не литерал в восьмеричной системе, но там префикс 0o). Вывод: ведущие нули — это проблема форматирования, а не хранения данных. Мы решаем задачу на уровне представления (UI, логгирование, экспорт).

Метод №1: Классика — String(format:)

Самый популярный ответ на Stack Overflow — использование функции String(format:), унаследованной из Objective-C (через мост с NSString). Это быстрый и лаконичный способ.

Пример: добавить 3 ведущих нуля

let number = 7
let formatted = String(format: "%04d", number)
print(formatted) // "0007"

Спецификатор %04d означает:

  • % — начало спецификатора;
  • 0 — заполнять пустые позиции нулями, а не пробелами;
  • 4 — минимальная ширина поля (4 символа);
  • d — десятичное целое число (Int).

Если число будет длиннее 4 символов (например, 12345), форматирование не обрежет его — вы получите «12345».

Плюсы и минусы

  • Плюсы: Просто, быстро, одна строка. Работает во всех версиях Swift.
  • Минусы: Использует NSString под капотом, что может быть чуть медленнее чистого Swift-решения. Нужно помнить синтаксис форматирования C-style. Не локализован (не учитывает разделители тысяч, если они нужны).

Когда использовать: Для простых случаев: логи, отладка, вывод ID, когда не нужна локализация.

Метод №2: Чистый Swift — String(repeating:count:) + суффикс

Если вы хотите избежать Objective-C моста и писать на «чистом» Swift, можно сделать это вручную. Это отличное упражнение для понимания строк.

extension Int {
    func leadingZeros(_ totalDigits: Int) -> String {
        let stringValue = String(self)
        let zerosCount = max(0, totalDigits - stringValue.count)
        return String(repeating: "0", count: zerosCount) + stringValue
    }
}

let number = 42
print(number.leadingZeros(5)) // "00042"

Как это работает?

  1. Превращаем Int в строку.
  2. Вычисляем, сколько нулей нужно добавить: totalDigits - length. Если число уже длинное, max(0, ...) защищает от отрицательного значения.
  3. Создаём строку из нужного количества нулей и приклеиваем её спереди.

Плюсы и минусы

  • Плюсы: Полностью на Swift, легко читается, можно кастомизировать (например, заменить «0» на другой символ).
  • Минусы: Создаёт промежуточные строки (немного менее эффективно, чем String(format:) для больших объёмов).

Когда использовать: Когда хочется контроля, или если вы уже используете кастомные расширения для Int.

Метод №3: Современный Swift 5.5+ — formatted()

Начиная с Swift 5.5 (iOS 15, macOS 12), у нас появился новый, элегантный способ форматирования — метод formatted() из протокола FormatStyle. Это самый «свифтовый» путь.

import Foundation

let number = 7
let formatted = number.formatted(.number.precision(.integerLength(3...3)))
print(formatted) // "007"

Что здесь происходит?

  • .number — выбираем стиль форматирования чисел.
  • .precision(.integerLength(3...3)) — указываем, что длина целой части должна быть ровно 3 символа. Swift сам добавит ведущие нули.

Можно настроить ещё больше: группировку, знаки, валюту.

let largeNumber = 1234
let withGrouping = largeNumber.formatted(.number.grouping(.never))
print(withGrouping) // "1234"

let withLeadingZeros = largeNumber.formatted(.number.precision(.integerLength(6...6)))
print(withLeadingZeros) // "001234"

Плюсы и минусы

  • Плюсы: Нативный Swift API, типобезопасный, легко читается, поддерживает локализацию «из коробки». Мощный.
  • Минусы: Требует iOS 15+/macOS 12+ (Swift 5.5). Для старых версий не подойдёт. Может быть избыточным для простых задач.

Когда использовать: В новых проектах, где не нужно поддерживать старые ОС. Идеально для UI, где уже используется Text со встроенным форматированием.

Метод №4: NumberFormatter — для сложных случаев

Если вам нужно не только добавить нули, но и локализовать вывод (например, в Германии разделитель тысяч — точка, а во Франции — пробел), NumberFormatter — ваш

Блоги

Рекомендаций по книгам