Добавление начальных нулей в строку без (ов) printf

#c

#c

Вопрос:

Я хочу добавить переменную с начальными нулями в строку. Я ничего не смог найти в Google, чтобы кто-нибудь не упомянул (s)printf , но я хочу сделать это без (s)printf .

Кто-нибудь из читателей знает способ?

Ответ №1:

Я могу предложить это однострочное решение, если вам нужно поле с n_zero нулями:

 auto new_str = std::string(n_zero - std::min(n_zero, old_str.length()), '0')   old_str;
  

Например, для std::string old_str = "45"; size_t n_zero = 4; вы получаете new_str == "0045" .

Комментарии:

1. Мне это нравится. Это означает, что мне не нужно создавать stringstream, у которого есть довольно большой багаж в отношении внутренних компонентов.

2. Очень хорошее решение! Что происходит, когда (n_zero — old_string. длина()) отрицательна? РЕДАКТИРОВАТЬ: Только что протестировал, похоже, что он все еще работает, передавая отрицательное значение.

3. @Castaa Аргументом для количества символов является std::string::size_type , который, как и большинство типов размера в stdlib, не имеет знака. Итак, если пользователь передает отрицательное число, оно оборачивается и приводит к большому положительному числу. Итак, это должно «работать», но, вероятно, не делать ожидаемую / полезную вещь (следовательно, почему типы размера без знака плохие, м’кей).

4. добавлено исправление, касающееся переполнения целых чисел

5. @lys добавил уточнение для ожидаемых типов, в частности, n_zero должно иметь тип size_t, тогда он также совместим с используемым нами конструктором std::string.

Ответ №2:

Вы могли бы использовать std::string::insert , std::stringstream с потоковыми манипуляторами или Boost.Форматировать :

 #include <string>
#include <iostream>
#include <iomanip>
#include <boost/format.hpp>
#include <sstream>

int main() {
  std::string s("12");
  s.insert(0, 3, '0');
  std::cout << s << "n";

  std::ostringstream ss;
  ss << std::setw(5) << std::setfill('0') << 12 << "n";
  std::string s2(ss.str());
  std::cout << s2;

  boost::format fmt("dn");
  fmt % 12;
  std::string s3 = fmt.str();
  std::cout << s3;
}
  

Комментарии:

1. Приложение: Для заполнения целого числа до 20 символов: auto padded = std::to_string(num); padded.insert(0, 20U - std::min(std::string::size_type(20), padded.length()), '0'); Это min предотвращает обтекание, если строка, которую вы пытаетесь дополнить, слишком длинная. (20 символов не будут иметь этой проблемы для любого целого числа младше 64 бит). Приведение к size_type необходимо, потому что min жалуется на несоответствия на некоторых платформах.

2. Я хотел бы, чтобы вы могли объяснить этот первый пример, используя std::string

Ответ №3:

Вы могли бы сделать что-то вроде:

 std::cout << std::setw(5) << std::setfill('0') << 1;
  

Это должно быть напечатано 00001 .

Однако обратите внимание, что символ заполнения является «липким», поэтому, когда вы закончите заполнять нулем, вам придется использовать std::cout << std::setfill(' '); , чтобы снова получить обычное поведение.

Комментарии:

1. Нет, спасибо за ваш вклад, но это тот же способ, что и при использовании sprintf (:

2. не кажется липким. std::cout << std::setw(5) << std::setfill('0') << 1 << 1 << std::endl; выдает: 000011

3. @AleksanderFular std::setw не является липким. std::setfill является липким, но от него мало толку без слишком большой ширины, чтобы дать ему что-то делать. Итак, ваш первый 1 получает setw(5) и, следовательно, имеет начальные нули перед собой, но затем setw возвращается к значению по умолчанию, так что ваш второй 1 просто печатается как 1 . Итак, 00001 1 = 000011 . Дело в том, что если вы позже установите setw , вы обнаружите, что предыдущий setfill символ все еще действовал, потому что setfill is not sticky => не сбрасывается значение пробела по умолчанию.

4. Именно то, что мне было нужно. Спасибо.

Ответ №4:

 // assuming that `original_string` is of type `std:string`:

std::string dest = std::string( number_of_zeros, '0').append( original_string);
  

Комментарии:

1. Разве это не просто добавит нули без учета длины «original_string»? number_of_zeros = 4 original_string = "99" dest will become: 000099 (and not 0099) . Пожалуйста, поправьте меня, если я ошибаюсь, или я, возможно, не понимаю, что на самом деле означают «начальные нули»…

2. @lepe Это отвечает на вопрос, как написано. Написал ли OP то, что они на самом деле имели в виду, это другой вопрос.

Ответ №5:

У меня это хорошо работает. Вам не нужно переключать setfill обратно на ‘ ‘, поскольку это временный поток.

 std::string to_zero_lead(const int value, const unsigned precision)
{
     std::ostringstream oss;
     oss << std::setw(precision) << std::setfill('0') << value;
     return oss.str();
}
  

Ответ №6:

Если вы хотите изменить исходную строку вместо создания копии, вы можете использовать std::string::insert() .

 std::string s = "123";
unsigned int number_of_zeros = 5 - s.length(); // add 2 zeros

s.insert(0, number_of_zeros, '0');
  

Результат:

 00123
  

Ответ №7:

 memcpy(target,'0',sizeof(target));
target[sizeof(target)-1] = 0;
  

Затем вставьте любую строку, с которой вы хотите, с префиксом нуля в конце буфера.

Если это целое число, помните, что log_base10(number) 1 (иначе ln(number)/ln(10) 1 ) дает вам длину числа.

Комментарии:

1. Нет, спасибо за попытку, но я хочу иметь возможность добавлять переменное количество нулей.

2. @Guus: Это является переменным числом нулей. Однако вы можете заменить (sizeof(target)) каким-либо другим числом, если это вас устроит.

3. @Guus: В частности, судя по вашему комментарию ниже, вы хотели d, верно? Если буфер имеет длину в шесть символов, это именно то, что мой код сделал бы для вас (по крайней мере, часть заполнения нулем, с указанием числа в конце, была оставлена для вас).