1

I have the string:

string str = "1234567890";

//Magic code

cout<<str<<endl;

Which i want to output: 12 34 56 78 90

I assume std has some neat feature/function to help solve this. How do I that in the most convenient way?

Alex
  • 365
  • 4
  • 17
  • 3
    There's no magic solution, using a simple for loop is convenient I'd say. – Hatted Rooster Jul 11 '17 at 10:17
  • Are those duplicate `5`s intended? That would probably change the correct answer a lot. i.e. do you want just to insert spaces between every 2 characters, or do you want to insert spaces at some magical junction, in this case, between adjacent odd and even numbers, while also stripping duplicate characters... Presumably the answer is the former. – underscore_d Jul 11 '17 at 11:03
  • 1
    What should happen if `str` contains an odd number of digits? Non-digits? Non-Graphical-characters? Spaces? – Deduplicator Jul 11 '17 at 11:06
  • Then you start wondering about Unicode characters and realise C++ still doesn't have an official Unicode string class :| (protip: in the meantime, use `ustring` from `glibmm`) – underscore_d Jul 11 '17 at 11:09
  • Did you try anything? – Lightness Races in Orbit Jul 11 '17 at 11:37

3 Answers3

2

The std::string::insert with a for loop could help you to insert spaces into an std::string very easely:

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

using namespace std;

int main() {
    string str = "1234567890";

    for(auto it = str.begin(); it != str.end(); it += min<int>(str.end() - it, 2))
        it = (it != str.begin() ? str.insert(it, ' ') + 1 : it);

    cout << str << endl;
}

The std::string::insert returns an iterator pointing to the character inserted, therefore it has to be incremented to step over the inserted character.

Because std::string has a random-access iterator it can be incremented or decremented more than by one. The min<int>(str.end() - it, 2) ensures that the next step won't go out of bounds.

Akira
  • 4,385
  • 3
  • 24
  • 46
1

A more general approach. Define a function that inserts a given character char_to_insert into a given string s every interval characters, excluding beginning and end of string:

std::string insert_char(const std::string& s, char char_to_insert, size_t interval)
{
    // corner cases
    if (!interval || !s.length()) return s;

    // compute number of characters to insert
    auto number_of_chars_to_insert = (s.length()-1)/interval;

    // compute total length
    auto output_length = s.length() + number_of_chars_to_insert;

    // pre-allocate output string with all characters equal to char_to_insert
    std::string retval(output_length, char_to_insert);

    // cycle input string, keeping track of position in input and output strings
    size_t pos = 0, pos_in_input = 0;
    for (const auto& c : s)
    {
        // copy from input to output
        retval[pos++] = c;

        // advance in output every interval chars
        if ((++pos_in_input) % interval == 0)
            ++pos;
    }
    return retval;
}

Then:

int main()
{
    std::string s = "1234567890";
    for (size_t i = 1; i != 5; ++i)
        std::cout << insert_char(s, ' ', i) << std::endl;
    return 0;
}

The output:

1 2 3 4 5 6 7 8 9 0
12 34 56 78 90
123 456 789 0
1234 5678 90
themiurge
  • 1,619
  • 17
  • 21
0

There is no built-in to do what you want. Instead, the most convenient solution is probably to iterate through the string and output pairs of digits as you go:

string str = "1234567890";
for (auto it = str.begin(); it != str.end(); ++it){
    std::cout << *(it);
    if (++it != str.end()){
        std::cout << *it << " ";
    }
}
std::cout << std::endl;

Or non-iterator version:

string str = "1234567890";
for (idx = 0; idx < str.length(); idx += 2){
    std::cout << str.substr(idx, 2) << " ";
}
std::cout << std::endl;

Both of these examples will have a trailing space on the line, but I've left it in to keep the examples simpler.

Baldrickk
  • 4,291
  • 1
  • 15
  • 27