how to triple space

Pages: 12
Hi guys, how can i triple every space from a given string?
Are you using std::string or c-style null-terminated string?
char array
i made a program but my it turns triple space in character because he is adding ascii values
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include<cstring>
using namespace std;

int main()
{
   char c[100];
   cout <<"Insert a string : "<<endl;
   cin.get(c,100);
   for(int i = 0; i<100; i++){
    if(c[i] == ' '){
    c[i] = c[i] * 3;
    }
}
    cout<<c;

    return 0;

}

Last edited on
how
Using std::string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <string>

int main()
{
	std::string c;

	std::cout << "Insert a string :\n";
	std::getline(std::cin, c);

	for (size_t p = 0; p < c.size(); ++p)
		if (c[p] == ' ') {
			c.insert(p, "  ");
			p +=2;
		}

	std::cout << c << '\n';
}



Insert a string :
aa bb cc dd
aa   bb   cc   dd

Last edited on
This is one way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <string>

std::string space_x3( const std::string& str )
{
    std::string result_string ;

    for( char c : str ) // for each char c in the string str
    {
        // if it is a space, append three spaces to result_string
        if( c == ' ' ) result_string += "   " ;
        else result_string += c ; // otherwise append the character as it is
    }

    return result_string ;
}

int main()
{
    std::string str ;
    std::cout << "enter a string: " ;
    std::getline( std::cin, str ) ;

    const std::string spaced_out_str = space_x3(str) ;
    std::cout << spaced_out_str << '\n' ;
}


http://coliru.stacked-crooked.com/a/5e507fba174e503f
c[i] = c[i] * 3;
C++ doesn't work that way. What this code actually does is take the numeric representation of c[i] (aka the ASCII value) and multiply it by 3, then it replaces the the i'th character (c[i]) with that new value.

You can also avoid the array or string altogether:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

int main()
{
    char ch;
    while (std::cin.get(ch)) {
	std::cout << ch;
	if (ch == ' ') {
	    std::cout << "  ";
	} else if (ch == '\n') {
	    break;
	}
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
   const int MAX = 100;
   char c[MAX+1];
   cout << "Insert a string: ";
   cin.get( c, MAX );
   int length = strlen( c );
   int nspace = 0;   for( int i = 0; i < length; i++ ) if ( c[i] == ' ' ) nspace++;
   int newlength = length + 2 * nspace;
   if ( newlength > MAX )
   {
      cout << "Out of luck!";
   }
   else
   {
      c[newlength] = '\0';
      for ( int i = length - 1, j = newlength - 1; i >= 0; i--, j-- )
      {
         c[j] = c[i];
         if ( c[i] == ' ' ) 
         {
            c[--j] = ' ';
            c[--j] = ' ';
         }
      }
      cout << c;
   }            
}


Insert a string: The answer, my friend, is blowin' in the wind
The   answer,   my   friend,   is   blowin'   in   the   wind 
Last edited on
i know
anyway thanks
> C++ doesn't work that way.

C++ can work that way with a suitable custom character type.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>
#include <string>
#include <string_view>

struct rchar // repeated char
{
    char c ;
    std::size_t cnt ;

    operator char() const noexcept { return c ; }

    rchar& operator+= ( std::size_t n ) noexcept { cnt += n ; return *this ; }
    rchar& operator*= ( std::size_t n ) noexcept { cnt *= n ; return *this ; }

    friend rchar operator+ ( rchar rc, std::size_t n ) noexcept { return rc += n ;}
    friend rchar operator+ ( std::size_t n, rchar rc ) noexcept { return rc += n ;}
    friend rchar operator* ( rchar rc, std::size_t n ) noexcept { return rc *= n ;}
    friend rchar operator* ( std::size_t n, rchar rc ) noexcept { return rc *= n ;}

    friend std::ostream& operator<< ( std::ostream& stm, const rchar& rc )
    {
        for( std::size_t i = 0 ; i < rc.cnt ; ++i ) stm << rc.c ;
        return stm ;
    }

    // TO DO: specialise std::char_traits for this char type
};

struct rc_string : public std::basic_string<rchar>
{
    using base = std::basic_string<rchar> ;

    rc_string( const std::string_view& str )
    {
        for( char c : str ) *this += c ;
    }

    rc_string( const std::string& str ) : rc_string( std::string_view(str) ) {}
    rc_string( const char* cstr ) : rc_string( std::string_view(cstr) ) {}

    base::size_type text_size() const
    {
        base::size_type sz = 0 ;
        for( const auto& rc : *this ) sz += rc.cnt ;
        return sz ;
    }

    rc_string& operator+= ( char c )
    {
        if( !empty() && back().c == c ) back() += 1 ;
        else static_cast<base&>(*this) += rchar{ c, 1 } ;
        return *this ;
    }

    friend std::ostream& operator<< ( std::ostream& stm, const rc_string& rc_str )
    {
        for( const auto& rc : rc_str ) stm << rc ;
        return stm ;
    }

    friend std::istream& getline( std::istream& stm, rc_string& rc_str )
    {
        std::string str ;
        if( std::getline( stm, str ) ) rc_str = str ;
        return stm ;
    }

    // TO DO: lots more stuff
};

int main()
{
    rc_string str = "aaaaa bb  cccccc   dddd" ;

    std::cout << str << '\n' ; // aaaaa bb  cccccc   dddd
    std::cout << "text size: " << str.text_size() << '\n' ; // 23
    std::cout << "#rchars: " << str.size() << '\n' ; // 7 (7 rchar segments)

    // triple every space in the string
    for( auto& c : str ) if( c == ' ' ) c *= 3 ;
    std::cout << '\n' << str << '\n' ; // aaaaa   bb      cccccc         dddd
    std::cout << "text size: " << str.text_size() << '\n' ; // 35
    std::cout << "#rchars: " << str.size() << '\n' ; // 7 (still only 7 rchar segments)

    std::cout << "\nenter a string: " ;
    getline( std::cin, str ) ;
    std::cout << str << '\n' ;
    std::cout << "text size: " << str.text_size() << '\n' ;
    std::cout << "#rchars: " << str.size() << '\n' ;

    // triple every space in the string
    for( auto& c : str ) if( c == ' ' ) c *= 3 ;
    std::cout << '\n' << str << '\n' ; // aaaaa   bb      cccccc         dddd
    std::cout << "text size: " << str.text_size() << '\n' ;
    std::cout << "#rchars: " << str.size() << '\n' ;
}


http://coliru.stacked-crooked.com/a/e296aed2535c7a9f
Using C string functions (strtok & strcat) to split a C string into tokens, concatenate each token to a destination C string and add 3 spaces:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <cstring>

int main()
{
   // a test C string
   char src_str[] = "This is a test string";

   std::cout << "Splitting \"" << src_str << "\" into tokens:\n\n";

   // get the first C string token, if any
   char* pch = std::strtok(src_str, " ");

   // create an empty destination C string
   char dest_str[100] { };

   // loop while there are valid C string tokens
   while (pch != nullptr)
   {
      // append the valid token to the destination C string
      std::strcat(dest_str, pch);

      // append 3 spaces to the C string
      std::strcat(dest_str, "   ");

      // get the next token
      pch = std::strtok(NULL, " ");
   }

   std::cout << dest_str << '\n';
}

http://www.cplusplus.com/reference/cstring/strtok/
http://www.cplusplus.com/reference/cstring/strcat/

Of course, this presumes the source C string is single-spaced. Multiple spaces in the source are treated as single spaces.
Last edited on
The issue with strtok() is that it modifies the specified string. The dest_str is right, but src_str is now not as before. src_str cannot be const even when a new string is being constructed.

1
2
std::cout << src_str << '\n';
std::cout << dest_str << '\n';


displays

Splitting "This is a test string" into tokens:

This
This   is   a   test   string


as the original ' ' has been replaced with NULL.
constructing a new string is the most efficient way, I believe.
then it is simply
1
2
3
4
5
6
7
8
9
10
11
12
13
char newstr[1000] = {0}; //important: newstr needs to be zero filled so terminal zero in place
char oldstr[] = "this is a test and stuff";

for(int i =0, j=0; i < strlen(oldstr); i++)
{
   if(oldstr[i] == ' ') //I can't think of a clean way to avoid this. 
     {
        newstr[j++] = ' ';
        newstr[j++] = ' ';
        
     }   
       newstr[j++] = oldstr[i]; //notice this gets the third space by copying the original.
}
Last edited on
Yes, std::strtok is destructive to the C string being tokenized. So? Where does the OP say they need to retain the original C string as being UN-modified? In their posted code the original C string is being modified.

src_str cannot be const even when a new string is being constructed.

So? Where does the OP state they have to use a constant C string?

If retaining an un-modified original C string is required they can either use other C string functions that don't modify the original, tokenize a copy of the original or any one of several different ways of modifying the original C string while creating a new C string that holds the modifications.

seeplus, the output you show is NOT from the code I posted. It looks as if you added an additional output statement. Only two outputs are in my code, before and after modifying the C string. Not when while doing the tokenization.

And whoever reported seeplus, stop!
Perhaps just use a standard FindAndReplace function.
It is sdt::string though, but the function may be handy for another time.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 


#include <string>
#include <iostream>
#define maximum 1000000

std::string FindAndReplace(const std::string& str, const std::string& match, 
        const std::string& replacement, unsigned int max_replacements = maximum)
{
    size_t pos = 0;
    std::string newstr = str;
    unsigned int replacements = 0;
    while ((pos = newstr.find(match, pos)) != std::string::npos
            && replacements < max_replacements)
    {
         newstr.replace(pos, match.length(), replacement);
         pos += replacement.length();
         replacements++;
    }
    return newstr;
}


int main()
{
		std::string a="ab cd ef gh ij kl   mn op";
			std::cout<<a<<std::endl;
		std::cout<<FindAndReplace(a," ","   ")<<std::endl;
		std::cout<<"Press enter to end . . ."<<std::endl;
		std::cin.get();
}
  
Last edited on
Yes, std::strtok is destructive to the C string being tokenized. So?


I was simply trying to make this point to those looking at this that didn't realize.

The real problem with using strtok() is that it skips consecutive delimiters. If you replace Furry Guy's source string with:
 
char src_str[] = "Expand one two  and three   spaces";


You get:
$ ./foo
Splitting "Expand one two  and three   spaces" into tokens:

Expand   one   two   and   three   spaces

The result should be:
Expand   one   two      and   three         spaces



Last edited on
Pages: 12