Avatar ·

Как дополнить строку нулями слева в Rust? Простой способ

Всем привет! Я начинаю изучать Rust и столкнулся с задачей, которая в других языках решается очень просто, а тут я что-то запутался. Мне нужно дополнить строку, представляющую число, нулями слева до определённой длины. Например, у меня есть число `42`, и я хочу получить строку `"00042"` (общая длина 5 символов). В Python я бы просто написал `str(42).zfill(5)`, в C# — `42.ToString("D5")`. А как это сделать в Rust? Я пробовал использовать `format!`, но пока не разобрался с синтаксисом. Вот мой код, который не работает так, как я хочу: ```rust fn main() { let num = 42; let padded = format!("{:05}", num); // Это работает для чисел println!("{}", padded); // Выводит "00042" } ``` Но проблема в том, что у меня не число, а уже строка! Допустим, я получил строку `"42"` из пользовательского ввода или из другого источника, и мне нужно дополнить её нулями слева. Как быть? Пробовал так: ```rust fn main() { let s = String::from("42"); let padded = format!("{:0>5}", s); // Ошибка! println!("{}", padded); } ``` Компилятор ругается, что `String` не реализует трейт для форматирования с шириной. Может, есть какой-то простой метод у строки, как `zfill` в Python? Или нужно преобразовывать в число и обратно? Подскажите, пожалуйста, самый простой и идиоматичный способ. Заранее спасибо! <<>>

Основной способ: метод format! с правильным синтаксисом

В Rust нет встроенного метода zfill, как в Python, но это легко делается с помощью макроса format!. Главное — понять синтаксис спецификаторов форматирования. Для строк используйте {:0>width$}, где width — это желаемая общая длина строки, а 0 — символ-заполнитель.

fn main() {
    let s = "42";
    let padded = format!("{:0>5}", s);
    println!("{}", padded); // Выведет: "00042"
}

Разберём синтаксис {:0>5}:

  • : — начало спецификатора форматирования.
  • 0 — символ, которым будет дополняться строка (в данном случае ноль).
  • > — выравнивание вправо (строка будет прижата к правому краю, а слева — заполнение).
  • 5 — минимальная ширина поля (общая длина результата).

Если ваша строка уже длиннее указанной ширины, ничего не произойдёт — строка останется как есть. Например:

let s = "123456";
let padded = format!("{:0>5}", s);
println!("{}", padded); // Выведет: "123456" (без изменений)

Работа с динамической шириной

Если ширина известна только во время выполнения, используйте синтаксис с width$:

fn pad_left(s: &str, width: usize) -> String {
    format!("{:0>width$}", s, width = width)
}

fn main() {
    let s = "42";
    println!("{}", pad_left(s, 5));  // "00042"
    println!("{}", pad_left(s, 8));  // "00000042"
}

Или можно передать ширину как отдельный аргумент:

fn pad_left(s: &str, width: usize) -> String {
    format!("{:0>1$}", s, width)
}

Здесь 1$ означает «использовать второй аргумент (с индексом 1) как ширину».

Если у вас String, а не &str

Метод format! принимает как &str, так и String (через авторазыменование). Просто передавайте строку по ссылке:

let s = String::from("42");
let padded = format!("{:0>5}", &s);
println!("{}", padded); // "00042"

Альтернатива: метод chars() и collect()

Если по какой-то причине вы не хотите использовать format!, можно сделать вручную:

fn pad_left_manual(s: &str, width: usize) -> String {
    if s.len() >= width {
        s.to_string()
    } else {
        "0".repeat(width - s.len()) + s
    }
}

fn main() {
    println!("{}", pad_left_manual("42", 5)); // "00042"
}

Но это менее идиоматично и медленнее, чем format!.

Важное замечание про Unicode

Метод format! с выравниванием считает количество байт, а не символов! Для ASCII-строк (цифры) это не имеет значения, но если у вас многобайтовые символы, результат может быть неожиданным. В таком случае используйте крейт unicode-width для корректного подсчёта ширины.

Итог

Самый простой способ дополнить строку нулями слева в Rust — использовать format!("{:0>width$}", s). Это кратко, эффективно и является стандартной практикой. Не нужно преобразовывать строку в число и обратно — просто используйте спецификатор форматирования.

<<>>

Альтернативный подход: метод rjust из крейта str_indices

Если вы часто работаете с дополнением строк (не только нулями, но и другими символами), можно написать небольшую функцию-утилиту:

fn rjust(s: &str, width: usize, pad_char: char) -> String {
    if s.len() >= width {
        s.to_string()
    } else {
        let padding = width - s.len();
        pad_char.to_string().repeat(padding) + s
    }
}

fn main() {
    println!("{}", rjust("42", 5, '0'));   // "00042"
    println!("{}", rjust("abc", 7, '*'));  // "****abc"
}

Этот подход даёт больше гибкости: вы можете задать любой символ для заполнения, а не только ноль. Однако он менее эффективен, чем format!, так как создаёт промежуточную строку через repeat.

Для чисел: форматирование напрямую

Если ваша исходная строка — это именно число, проще всего сначала преобразовать её в число, а потом отформатировать с нулями:

fn pad_number(s: &str, width: usize) -> String {
    let num: i32 = s.parse().expect("Не число");
    format!("{:0width$}", num, width = width)
}

fn main() {
    println!("{}", pad_number("42", 5)); // "00042"
}

Этот способ использует числовое форматирование, которое автоматически добавляет нули слева. Но он требует, чтобы строка гарантированно была числом, иначе будет паника. Для пользовательского ввода лучше использовать parse с обработкой ошибок.

Когда какой способ выбрать?

  • format! — для простых случаев, когда нужно дополнить нулями или одним символом.
  • Своя функция — если нужна гибкость (разные символы) или вы хотите избежать макросов.
  • Через число — если вы уверены, что строка — это число, и хотите использовать встроенное форматирование чисел.