Word Wrap Function

Hi all, I wanted to practice my beginner skills with a little text game, but I want a word wrap function to format the text properly. I found this one that looks promising, but I can't figure out how to use it.

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
/*
   This function takes a string and an output buffer and a desired width. It then copies
   the string to the buffer, inserting a new line character when a certain line
   length is reached.  If the end of the line is in the middle of a word, it will
   backtrack along the string until white space is found.
 */
 
#include <string.h>
#include <ctype.h>
 
char* word_wrap (char* buffer, char* string, int line_width) {
    int i = 0;
    int k, counter;
 
    while(i < strlen( string ) )
    {
        // copy string until the end of the line is reached
        for ( counter = 1; counter <= line_width; counter++ )
        {
            // check if end of string reached
            if ( i == strlen( string ) )
            {
                buffer[ i ] = 0;
                return buffer;
            }
            buffer[ i ] = string[ i ];
            // check for newlines embedded in the original input
            // and reset the index
            if ( buffer[ i ] == '\n' )
            {
                counter = 1;
            }
            i++;
        }
        // check for whitespace
        if ( isspace( string[ i ] ) )
        {
            buffer[i] = '\n';
            i++;
        }
        else
        {
            // check for nearest whitespace back in string
            for ( k = i; k > 0; k--)
            {
                if ( isspace( string[ k ] ) )
                {
                    buffer[ k ] = '\n';
                    // set string index back to character after this one
                    i = k + 1;
                    break;
                }
            }
        }
    }
    buffer[ i ] = 0;
 
    return buffer;


Can anyone tell me the correct usage for this code? I'm not sure what "buffer" is supposed to be when calling the function.
buffer is the result (it's also the returned value). Make buffer at least the the size of string
Hi coder777, thanks for the reply. Could you give an example of the function in use?

Like word_wrap(x, "blah blah blah", 80)?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

// your function

int main(void) {
    // example message
    const char* message = "Testing 1 2 3 4 This is a message";

    // buffer for storing the resultant string - make sure its large enough!
    char buffer[40] = {0}; 

    printf("Message:\n%s\n", word_wrap(buffer, message, 15));
    return 0;
}
Message:
Testing 1 2 3 4
This is a
message

Note that you should really change the second parameter to take const char* rather than char* - otherwise the above example (shouldn't) compile due to the casting away of qualifiers.
Ahh wonderful! Thank you so much for the help!
Shoot, I forgot to ask something. How would this work when using variables mid-sentence?

Example:

const char* room1 = "Your name is " player_name " and you're super kewl!"

Obviously this doesn't work. Would I have to just keep making new sentence variables for each variable that breaks a sentence?
Are you using C++ or C?
If you are using C++, its quite easy. Just use a std::string, and you can add variables to it, or you could use std::stringstream:
1
2
std::string room1 = "Your name is" + std::string(player_name) + " and you're super kewl!";
word_wrap(buffer, room1.c_str(), 20);


If you are using C, you should instead use snprintf, like this:
1
2
char message[256];
snprintf(message, 255, "Your name is %s and you're super kewl!", player_name);
Hi, I hate to bother you about this again, but I can't get the + operators to work. For example:

char buffer[3000] = {0};

const char* finalize = "Your name is " + string(player_name) + " and you're " + string(age) + " years old. You're a " + string(gender) + " and your body type is " + int(body) + ".";

cout << (word_wrap(buffer, finalize, 80);

Trying to use this spits out the following error:
error: no match for 'operator+' (operand types are 'std::basic_string<char>' and 'int')

Any ideas? I tried using finalize.c_str() as well, same error... can't get this working.
You are using char arrays, rather than std::string. I'm going to assume you are using C++ (from your error message). You need to use the to_string function to convert:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <string>
//...

char buffer[3000] = {0};
/* Assuming:
std::string player_name;
int age;
std::string gender;
std::string body;
*/

std::string finalize = "Your name is " + player_name + " and you're " + std::to_string(age) + 
                       " years old. You're a " + gender + " and your body type is " + body + ".";
word_wrap(buffer, finalize.c_str(), 80);
cout << buffer << '\n';


You'll also need to have a compiler with C++11 - VS is enable by default, for GCC or Clang you'll need to add it yourself (normally with -std=c++11).
Last edited on
I really appreciate your help, but I still can't get it to work even when copy/pasting verbatim. I'm going to post the entire code so far, maybe you could figure out what's wrong? I'm getting "to string is not a member of std." C++11 is enabled. Also, in this case age is handled as a string, and body is an int. When removing to_string and putting age as just "age", I get the same operator+ error from before.

http://pastebin.com/e2v4pP1v
Some compilers don't have the std::to_string function implemented yet for certain systems.

You can just make your own to_string function if you think you're running one of those:
1
2
3
4
5
6
7
8
9
// You'll need to #include <sstream>
// Just stick this at the top somewhere...
template <typename T>
std::string to_string(const T& x)
{
    std::ostringstream oss;
    oss << x;
    return oss.str();
}
(If you end up using this one, make sure you don't use std:: when you call it)
Excellent! The manual to_string function fixed everything. Once again, thank you guys for the help and education!
Well... I'm unfortunately back again. I seem to have a never ending supply of problems getting this code to work the way I want it to. Here's the problem now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Finalize character.
    char finalize_B[3000] = {0};
    std::string finalize_S = "Your name is " + player_name + " and you're " + age + " years old. You're a " + gender + " and your body type is ";
    word_wrap(finalize_B, finalize_S.c_str(), 80);
    cout << endl << finalize_S;
    if (body == 1)
    {
        char finalizewhale_B[3000] = {0};
        string finalizewhale_S = "fat and blubbery.";
        word_wrap(finalizewhale_B, finalizewhale_S.c_str(), 80);
        cout << finalizewhale_S << endl;
    }
    else if (body == 2)
    {
        char finalizeburly_B[3000] = {0};
        string finalizeburly_S = "burly and strong.";
        word_wrap(finalizeburly_B, finalizeburly_S.c_str(), 80);
        cout << finalizeburly_S << endl;
    }


Using the function inside of if checks to append additional strings breaks the ability to word wrap. Does anyone know if this is easily fixable?
Bump. :(
You could go for a more C++-ish approach and avoid the raw character arrays altogether.

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
#include <iostream>
#include <string>
#include <cctype>

std::string word_wrap(std::string text, unsigned per_line)
{
    unsigned line_begin = 0;

    while (line_begin < text.size())
    {
        const unsigned ideal_end = line_begin + per_line ;
        unsigned line_end = ideal_end <= text.size() ? ideal_end : text.size()-1;

        if (line_end == text.size() - 1)
            ++line_end;
        else if (std::isspace(text[line_end]))
        {
            text[line_end] = '\n';
            ++line_end;
        }
        else    // backtrack
        {
            unsigned end = line_end;
            while ( end > line_begin && !std::isspace(text[end]))
                --end;

            if (end != line_begin)                  
            {                                       
                line_end = end;                     
                text[line_end++] = '\n';            
            }                                       
            else                                    
                text.insert(line_end++, 1, '\n');
        }

        line_begin = line_end;
    }

    return text;
}

int main()
{
    std::string player_name = "Eric";
    std::string age = "152";
    std::string gender = "transgender";

    enum body_type { fit, unfit };
    body_type body = fit;

    std::string working_text = "Your name is " + player_name + " and you're " + age + " years old. You're a " + gender + " and your body type is ";

    std::cout << word_wrap(working_text, 10) << "\n\n" ;
    std::cout << word_wrap(working_text + (body == fit ? "burly and strong." : "fat and blubbery."), 10) << '\n';
}


http://ideone.com/wai9da


[Edit: Note that there is a bug in the code as originally posted -- corrected now.]
Last edited on
So why cout << endl << finalize_S;? I'd expect that it'd be _B

On line 9/16 you do not append. To append you need to do this:

string finalizewhale_S = finalize_S + "fat and blubbery."
Hi coder777, I tried your method, but it breaks the wordwrapping of finalize_S, and only applies the word wrap to the "fat and blubbery" part.

I think I give up on this word wrap... for such a simple thing it feels like rocket science to a beginner like me and it's way more frustration than it's worth. I'm going to try cire's wordwrap function later, hopefully it'll work the way I want it to, otherwise I give up.

Thanks everyone for all the time you took to help, I really appreciate it.
Looking at it now, there's still an error in the code. The <= on line 12 should just be <.
Topic archived. No new replies allowed.