49

I want to add a variable of leading zero's to a string. I couldn't find anything on Google, without someone mentioning (s)printf, but I want to do this without (s)printf.

Does anybody of the readers know a way?

user438383
  • 5,716
  • 8
  • 28
  • 43
Guus Geurkink
  • 643
  • 2
  • 7
  • 11

7 Answers7

124

I can give this one-line solution if you want a field of n_zero zeros:

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

For example, for std::string old_str = "45"; size_t n_zero = 4; you get new_str == "0045".

Ruslan Guseinov
  • 1,241
  • 2
  • 8
  • 5
  • 6
    I like this. It means I don't have to construct a stringstream, which has quite some baggage with respect to internals. – Robinson Jan 29 '16 at 12:14
  • 2
    Very nice solution! What happens when (n_zero - old_string.length()) is negative? EDIT: Just tested it, it appears to still work passing a negative value. – Castaa Apr 06 '18 at 05:32
  • 1
    @Castaa The argument for the number of characters is an `std::string::size_type`, which like most size types in the stdlib is unsigned. So, if the user passes a negative number, that gets wrapped around and will result in a large positive number. So, it should "work" but probably not do the expected/useful thing (hence why unsigned size types are bad, m'kay). – underscore_d Jan 21 '20 at 14:57
  • added a fix concerning the integer overflow – Ruslan Guseinov Nov 12 '21 at 09:22
  • @RuslanGuseinov `string.length()` returns `size_t` which `std::min` complains about. – lys Jul 17 '22 at 07:38
  • 1
    @lys added a clarification for expected types, in particular n_zero should be of type size_t, then it is also compatible with std::string constructor that we use. – Ruslan Guseinov Aug 22 '22 at 11:42
66

You could use std::string::insert, std::stringstream with stream manipulators, or Boost.Format :

#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("%05d\n");
  fmt % 12;
  std::string s3 = fmt.str();
  std::cout << s3;
}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • An application: To pad out an integer to 20 characters: `auto padded = std::to_string(num); padded.insert(0, 20U - std::min(std::string::size_type(20), padded.length()), '0');` The `min` keeps you from wrapping around if the string you are trying to pad is too long. (20 characters won't have this problem for any integer under 64 bits). The cast to `size_type` is needed because min complains about mismatches on some platforms. – Eponymous Aug 29 '17 at 21:38
  • I wish you could explain that first example using `std::string` – Jeff Jun 04 '19 at 14:22
32

You could do something like:

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

This should print 00001.

Note, however, that the fill-character is "sticky", so when you're done using zero-filling, you'll have to use std::cout << std::setfill(' '); to get the usual behavior again.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Nah, thanks for your input but its the same way using sprintf (: – Guus Geurkink May 26 '11 at 19:33
  • 2
    does not seem to be sticky. `std::cout << std::setw(5) << std::setfill('0') << 1 << 1 << std::endl;` produces: `000011` – Aleksander Fular Apr 14 '16 at 13:37
  • 1
    @AleksanderFular `std::setw` is not sticky. `std::setfill` is sticky, but it's not much use without an oversized width to give it something to do. So your first `1` gets the `setw(5)` and hence has leading zeroes prepended, but then the `setw` is dropped back to default, so your second `1` just gets printed as `1`. So, `00001` + `1` = `000011`. The point is that if you later set `setw`, you'd find that the previous `setfill` character was still in effect, because `setfill` isn't sticky => doesn't get reset to its default of a space. – underscore_d Oct 03 '16 at 16:22
  • Exactly what I needed. Thanks. – Rapti Dec 12 '16 at 21:12
15
// assuming that `original_string` is of type `std:string`:

std::string dest = std::string( number_of_zeros, '0').append( original_string);
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 40
    Doesn't this will just add zeros without taken into account the "original_string" length? `number_of_zeros = 4 original_string = "99" dest will become: 000099 (and not 0099)`. Please correct me if I'm wrong or I perhaps don't understand what 'leading zeros' really mean... – lepe Jul 06 '15 at 04:05
  • 6
    @lepe It answers the question as written. Whether the OP wrote what they really meant is a different matter. – underscore_d Oct 03 '16 at 16:21
8

This works well for me. You don't need to switch setfill back to ' ', as this a temporary stream.

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();
}
Ivan Strelets
  • 232
  • 3
  • 4
5

If you want to modify the original string instead of creating a copy, you can use 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');

Result:

00123
Genhis
  • 1,484
  • 3
  • 27
  • 29
1
memcpy(target,'0',sizeof(target));
target[sizeof(target)-1] = 0;

Then stick whatever string you want zero prefixed at the end of the buffer.

If it is an integer number, remember log_base10(number)+1 (aka ln(number)/ln(10)+1) gives you the length of the number.

Seth Robertson
  • 30,608
  • 7
  • 64
  • 57
  • Nah, thanks for the try but I want to be able to add a variable amount of zero's. – Guus Geurkink May 26 '11 at 19:19
  • @Guus: That *is* a variable number of zeros. However, you can replace the (sizeof(target)) with some other number if it would make you happy. – Seth Robertson May 26 '11 at 19:21
  • @Guus: Specifically, from your comment below, you wanted %05d, right? If the buffer is six characters long, that is exactly what my code would do for you (at least the zero fill part, putting the number at the end was left for you). – Seth Robertson May 26 '11 at 19:23