Erasing all but one whitespace from strings of consecutive whitespace charaters in a string

My program asks the user to enter a line of text ended with a period. It removes any spaces at the very beginning of the sentence. It then changes all the characters to lowercase except the very first letter in the sentence, which it capitalizes. The next part of my program is supposed to erase multiple consecutive whitespace characters leaving just one space between words.

This is the only usage of single and double quotes that doesn't give me any red squiggly underline warnings in my function remove_extra_blanks:
1
2
3
4
		if (((next != " ") && (next != "\n")) && ((last == " ") || (last == "\n")))
			temp.at(i) = ' ';
		else if ((next != " ") && (next != "\n"))
			temp.at(i) = s.at(i);

The function looks at each character in the string one by one to see if it is a space character, a new line character, or neither. Based on that it decides which characters to copy into the temp string.

I get red squiggly underline warnings under != and == when I use single quotations when comparing string characters for equality:
1
2
3
4
if (((next != ' ') && (next != '\n')) && ((last == ' ') || (last == '\n')))
			temp.at(i) = ' ';
		else if ((next != ' ') && (next != '\n'))
			temp.at(i) = s.at(i);

But if I use double quotations when assigning a space to an element of my temp string I get a red squiggly underline warning under the = in
temp.at(i) = ' '; :
1
2
3
4
if (((next != " ") && (next != "\n")) && ((last == " ") || (last == "\n")))
			temp.at(i) = " ";
		else if ((next != " ") && (next != "\n"))
			temp.at(i) = s.at(i);


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
#include <iostream>
#include <string>
using namespace std;

string remove_leading_blanks(const string& s);
string make_lower(const string& s);
string remove_extra_blanks(const string& s);

int main()
{
	string sentence;

	cout << "Enter a line of input up to 100 characters:\n";
	getline(cin, sentence);
	cout << "The sentence read in is:\n"
		<< sentence << endl;
	sentence = remove_leading_blanks(sentence);
	sentence = make_lower(sentence);	
	cout << "The sentence with the leading blanks removed\n"
	"and all but the first letter changed to lowercase is:\n"
		<< sentence << endl;
	sentence = remove_extra_blanks(sentence);
	cout << "The sentence with all extra whitespaces corrected is:\n"
		<< sentence << endl;
	system("pause");
	return 0;
}
string remove_leading_blanks(const string& s)
{
	string no_leading; //initialized to empty string
	int s_length = s.length();
	int index = 0;
	while ((!isdigit(s[index])) && (!isalpha(s[index])))
		index++;
	for (int i = index; i < s_length; i++)
		no_leading = no_leading + s[i];
	return no_leading;
}
string make_lower(const string& s)
{
	string temp(s);
	temp[0] = toupper(s[0]);
	for (int i = 1; i < s.length(); i++)
		temp[i] = tolower(s[i]);
	return temp;
}
string remove_extra_blanks(const string& s)
{
	string last = "z";
	string temp; //initialized to empty string
	for (int i = 0; i < s.length(); i++)
	{
		string next = s.substr(i, 1); //A one character string
		
		if (((next != " ") && (next != "\n")) && ((last == " ") || (last == "\n")))
			temp.at(i) = ' ';
		else if ((next != " ") && (next != "\n"))
			temp.at(i) = s.at(i);

		/*if (((next != ' ') && (next != '\n')) && ((last == ' ') || (last == '\n')))
			temp.at(i) = ' ';
		else if ((next != ' ') && (next != '\n'))
			temp.at(i) = s.at(i);*/

		/*if (((next != " ") && (next != "\n")) && ((last == " ") || (last == "\n")))
			temp.at(i) = " ";
		else if ((next != " ") && (next != "\n"))
			temp.at(i) = s.at(i);*/

		last = next;
	}
	return temp;
}
Last edited on
Use the find and replace functions:

http://www.cplusplus.com/reference/string/string/find/
http://www.cplusplus.com/reference/string/string/replace/

Example:
1
2
3
4
5
std::string::size_type pos;
while((pos = s.find("  ")) != std::string::npos)
{
  s.replace(pos, 2, " ");
}
Not tested!
Last edited on
Another option are regular expressions.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <string>
#include <regex>

using namespace std;

int main ()
{
  regex re("\\s{2,}");

  string input = "Bla    Bla Bla           Bla";
  string fmt = " ";
  string output = regex_replace(input, re, fmt);

  cout << "Before: " << input << "\n\n";
  cout << "After: " << output << "\n\n";
  system("pause");
  return 0;
}
Find/replace and regular expressions will work and they are easy to code, but find/replace is slow when the strings are big, and regular expressions will bloat your code by pulling in a large library.

The problem that you're having comes from confusing double-quotes and single-quotes. Single quotes contain chars. Double quotes contain c-strings. So at lines 60-63 you're trying to compare a string to a character.

Since next is always a single character, I'd code it that way by changing lines 49 and 53 to
char last = 'z'; and
char next = s[i];

Better yet, since next goes through all the characters in the string, you can use a range-based for loop by replacing lines 51-53 with
for (char next : s) {

All the comparisons with next should use single quotes. E.g.:
if (((next != ' ') && (next != '\n')) && ((last == ' ') || (last == '\n')))

temp.at(i) = ' '; won't work. at[] must refer to an existing character in the string. You want to add a new character. No worries, just use += instead:
temp += ' ';

You could simplify the code somewhat by recognizing that you're dividing each character into two kinds: "spaces" and "not spaces." If you record the next character's kind and the last character's kind, the code gets easier.
Thank you! My program is running without errors now.
Topic archived. No new replies allowed.