Help with Line Justification

Hello! I am having some troubles with a line justification program. The program is supposed to be written using strings. It allows a user to input a string of text, and then justifies the text to be 75 characters by first adding 2 spaces after punctuation marks, and then adding random spaces between words. We were instructed to use srand(time(nullptr)) and rand() for the random spaces, and to use find_first_of(whitespace) and find_first_not_of(whitespace)to locate the beginning and ending of words. So far I have successfully added spaces after the punctuation marks, but I am at a complete loss with the spaces between words. If anyone is willing to help me out I would be incredibly grateful!!


Here is the code I have written so far (the portion of the code that adds spaces between words is not complete):
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
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
#include "justify.h"

using std::cout; using std::cin; using std::endl; using std::string;
const int sizeString = 75;

void commaSpace(string &s) {
	int pos = s.find(',');
	while (pos != string::npos && s.size() < sizeString) {
		s.insert(pos + 1, 2, ' ');
		pos = s.find(',', pos + 1);
	}
}

void periodSpace(string &s) {
	int pos = s.find('.');
	while (pos != string::npos && s.size() < sizeString) {
		s.insert(pos + 1, 2, ' ');
		pos = s.find('.', pos + 1);
	}
}

void exclamationSpace(string &s) {
	int pos = s.find('!');
	while (pos != string::npos && s.size() < sizeString) {
		s.insert(pos + 1, 2, ' ');
		pos = s.find('!', pos + 1);
	}
}

void questionSpace(string &s) {
	int pos = s.find('?');
	while (pos != string::npos && s.size() < sizeString) {
		s.insert(pos + 1, 2, ' ');
		pos = s.find('?', pos + 1);
	}
}

void semiSpace(string &s) {
	int pos = s.find(';');
	while (pos != string::npos && s.size() < sizeString) {
		s.insert(pos + 1, 2, ' ');
		pos = s.find(';', pos + 1);
	}
}

int main() {
	string line;
	cout << "Enter a string: " << endl;
	getline(cin, line);
	const int sizeString = 75;

	if (line.size() < sizeString) {
		commaSpace(line);
	}
	cout << line << endl;
	cout << line.size() << endl;

	if (line.size() < sizeString) {
		periodSpace(line);
	}
	cout << line << endl;
	cout << line.size() << endl;

	if (line.size() < sizeString) {
		exclamationSpace(line);
	}
	cout << line << endl;
	cout << line.size() << endl;

	if (line.size() < sizeString) {
		questionSpace(line);
	}
	cout << line << endl;
	cout << line.size() << endl;

	if (line.size() < sizeString) {
		semiSpace(line);
	}
	cout << line << endl;
	cout << line.size() << endl;

	while (line.size() < sizeString) {
		int position = line.find_first_of(' ');
		srand(time(nullptr));
	}
	cout << line << endl;
	cout << line.size() << endl;
}
When you find yourself doing the same thing over and over, that is a hint that you are working too hard.

Let’s look at a simplified exemplar of the problem: justifying a line to 20 characters.

  01234567890123456789
  Hello! 'Sup yo?

(1)
Make sure that punctuation marks have TWO spaces following.

THINK:
Obviously, we don't want to add spaces after things like ' in don't .
Also, when we are done, we DON'T want to see:

  01234567890123456789
  H...        ...yo?
                    ^^ not justified!

We DO want to see:

  01234567890123456789
  H...          ...yo?
                    ^ yay! justified!

The easiest way already suggests itself.
Find a punctuation mark that is ALREADY followed by a space.

  01234567890123456789
  Hello! 'Sup yo?
       ^this    X: not this, there is not any space after this
                 (there shouldn't be, anyway)

Hmm... We might want to trim() our string before doing anything else.

Okay, so far, our algorithm is:

  (1) trim the string of leading and trailing whitespace
  (2) replace <punct><space> with <punct><space><space>

Great!

  01234567890123456789
  Hello!  'Sup yo?

Now we want to RANDOMLY widen spaces until we make the line exactly
20 characters long.

There are quite a few ways to do this, but I will suggest something
exceedingly simple: Get a random number to ANY element of the string,
and if that element is a space, then make it two spaces.
1
2
3
4
  while (s.length < max length):
    n ← get a random number in the range 0..(s.length - 1)
    if s[n] is a space:
      insert an additional space before s[n]

Let's see it in action:


  01234567890123456789
  Hello!  'Sup yo?
     ↑ nope

  01234567890123456789
  Hello!  'Sup yo?
            ↑ nope

  01234567890123456789
  Hello!  'Sup yo?
        ↑ yeah!

  01234567890123456789
  Hello!   'Sup yo?
   ↑ nope

  01234567890123456789
  Hello!   'Sup yo?
               ↑ yeah!

  01234567890123456789
  Hello!   'Sup  yo?

  <skip some steps>

  01234567890123456789
  Hello!    'Sup   yo?

Yeah!

So or revised algorithm is:

  (1) trim the string of leading and trailing whitespace
  (2) replace <punct><space> with <punct><space><space>
  (3) do our cool random space insert loop


The trick, now that you have a working algorithm, is to translate it to code.

For part (1), make yourself a function that looks like this:
1
2
3
4
5
6
  std::string trim( const std::string& s )
  {
    string result;
    // what goes here? //
    return result;
  }


Part (2) will require a loop: look at each character of the string until you find a punctuation character. std::ispunct() from #include <cctype> will help you here. If the very next character is a space, then add a space:

1
2
3
4
5
  for (int n = 0; n < (s.size() - 1); n++)
  {
    if (std::ispunct( s[n] ) && std::isspace( s[n+1] ))
      s.insert( n+1, 1, ' ' );
  }

There's a freebie for you.

Finally, for part (3) you will need to implement the pseudo-code algorithm I gave you above.


Hope this helps.
Topic archived. No new replies allowed.