DarenW
DarenW

Reputation: 16906

How to insert an integer with leading zeros into a std::string?

In a C++14 program, I am given a string like

std::string  s = "MyFile####.mp4";

and an integer 0 to a few hundred. (It'll never be a thousand or more, but four digits just in case.) I want to replace the "####" with the integer value, with leading zeros as needed to match the number of '#' characters. What is the slick C++11/14 way to modify s or produce a new string like that?

Normally I would use char* strings and snprintf(), strchr() to find the "#", but figure I should get with modern times and use std::string more often, but know only the simplest uses of it.

Upvotes: 5

Views: 3652

Answers (6)

max66
max66

Reputation: 66200

What is the slick C++11/14 way to modify s or produce a new string like that?

I don't know if it's slick enough but I propose the use of std::transform(), a lambda function and reverse iterators.

Something like

#include <string>
#include <iostream>
#include <algorithm>

int main ()
 {
   std::string str { "MyFile####.mp4" };
   int         num { 742 };

   std::transform(str.rbegin(), str.rend(), str.rbegin(),
                    [&](auto ch) 
                     {
                       if ( '#' == ch )
                        {
                          ch   = "0123456789"[num % 10]; // or '0' + num % 10;
                          num /= 10;
                        }

                       return ch;
                     } // end of lambda function passed in as a parameter
                  ); // end of std::transform() 

   std::cout << str << std::endl;  // print MyFile0742.mp4
 }  

Upvotes: 5

user5550963
user5550963

Reputation:

WHy not use std::stringstream and than convert it to string.

std::string inputNumber (std::string s, int n) {
   std::stringstream sstream;
   bool numberIsSet = false;
   for (int i = 0; i < s; ++i) {
      if (s[i] == '#' && numberIsSet == true)
         continue;
      else if (s[i] == '#' && numberIsSet == false) {
         sstream << setfill('0') << setw(5) << n;
         numberIsSet = true;
      } else
         sstream << s[i];
   }

   return sstream.str();
}

Upvotes: 2

Zan Lynx
Zan Lynx

Reputation: 54325

Mine got out of control while I was playing with it, heh.

Pass it patterns on its command line, like:

./cpp-string-fill file########.jpg '####' test###this### and#this

#include <string>
#include <iostream>
#include <sstream>

std::string fill_pattern(std::string p, int num) {
    size_t start_i, end_i;
    for(
        start_i = p.find_first_of('#'), end_i = start_i;
        end_i < p.length() && p[end_i] == '#';
        ++end_i
    ) {
        // Nothing special here.
    }

    if(end_i <= p.length()) {
        std::ostringstream os;
        os << num;
        const std::string &ns = os.str();
        size_t n_i = ns.length();
        while(end_i > start_i && n_i > 0) {
            end_i--;
            n_i--;
            p[end_i] = ns[n_i];
        }
        while(end_i > start_i) {
            end_i--;
            p[end_i] = '0';
        }
    }

    return p;
}

int main(int argc, char *argv[]) {
    if(argc<2) {
        exit(1);
    }
    for(int i = 1; i < argc; i++) {
        std::cout << fill_pattern(argv[i], 1283) << std::endl;
    }
    return 0;
}

Upvotes: 1

Dominik Stuchl&#237;k
Dominik Stuchl&#237;k

Reputation: 41

I would use regex since you're using C++14:

#include <iostream>
#include <regex>
#include <string>
#include <iterator>

int main()
{
    std::string text = "Myfile####.mp4";
    std::regex re("####");
    int num = 252;

    //convert int to string and add appropriate number of 0's
    std::string nu = std::to_string(num);
    while(nu.length() < 4) {
        nu = "0" + nu;
    }

    //let regex_replace do it's work
    std::regex_replace(std::ostreambuf_iterator<char>(std::cout),
                       text.begin(), text.end(), re, nu);
    std::cout << std::endl;

    return 0;
}

Upvotes: 4

kpie
kpie

Reputation: 11090

I would probably do something like this:

using namespace std;
#include <iostream>
#include <string>

int main()
{
    int SomeNumber = 42;
    string num = std::to_string(SomeNumber);
    string guide = "myfile####.mp3";
    int start = static_cast<int>(guide.find_first_of("#")); 
    int end = static_cast<int>(guide.find_last_of("#"));
    int used = 1;
    int place = end;
    char padding = '0';
    while(place >= start){
        if(used>num.length()){
            guide.begin()[place]=padding;
        }else{
            guide.begin()[place]=num[num.length()-used];
        }
        place--;
        used++;
    }
    cout << guide << endl; 

   return 0;
}

Upvotes: 0

kpie
kpie

Reputation: 11090

I would probably use something like this

#include <iostream>
using namespace std;

int main()
{
    int SomeNumber = 42;
    std:string num = std::to_string(SomeNumber);
    string padding = "";
    while(padding.length()+num.length()<4){
        padding += "0";
    }
    string result = "MyFile"+padding+num+".mp4";
    cout << result << endl; 

   return 0;
}

Upvotes: 1

Related Questions