Help with String - Converting upper/lower case

Hello everyone, I'm trying to write a program that will reformat the first letter of each word to capitalized and the remaining letters are lower case;

Sample Input:
aIReshire laMEnT

Expected Output:
Aireshire Lament

So I came up with the following code, however it
below is part of my function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  void convert_song(string&songname)
{
//Given the name of the song, this function will reformat                               //the first letter of each word to capitalized and the remaining letters are //lower case
// The code will first convert every nonspace character to lowercase.
// Then the first letter after each space will be reformatted to uppercase.
                                                                                                                                                                                                         
  for (int i = 0; i < songname.length(); i ++)
    {
       if (songname [i] !=' ')
        songname[i] = tolower(songname[i]);
       if (songname[i] == ' ')
       songname[i+1] = toupper(songname[i+1]);
                                                                                                                                                                                                                                              
    }

}


And I got the following output instead:

 aireshire lament

Thank you for any help.
What is the question exactly?
Hello, my question is , the code above does not work as I expected. I want to convert something like:

aIReshire laMEnT to Aireshire Lament.

But instead I got aireshire lament.

I'm trying to see what should I change about my code to make it work. (or any logical error in my code.)

Thank you.
The error is basically that whenever you find a space you convert the following letter to uppercase, but in the next iteration of the loop that letter is examined, and since it's not a space it is converted to lowercase.
Also, you didn't consider that the very first letter should always be uppercase.

To check for spaces I'd use isspace() which also checks for newlines and tabs.
Thank you for the reply. I apologize that I forgot to mention the very first character in the input will always be a blankspace. Which mean songname[0] will be a blankspace all the time, therefore I didn't convert the very first letter to be uppercase.

Another question,

Since I put tolower(songname[i]) before toupper (songname[i]) in my loop. Wouldn't my loop convert every letter to lowercase first, and then it convert the first letter after each blankspace to uppercase?

Sorry about the confusion.

Thank you.
Oh nevermind, I know what is wrong with my loop now. It converts a nonblank character to lower case. If the character is a
Blank then it converts the next character to upper case, but on the next time through the loop
The character you just capitalized is now converted to lower case
I have figured out a way to fix the error! Thank you very much for the help.

This thread can now be closed.
Wouldn't my loop convert every letter to lowercase first, and then it convert the first letter after each blankspace to uppercase?

Nope. A loop restarts when the flow of control reaches the end of the loop body or if it encounters a "continue" instruction. You loop checks if a character is not a space, then checks if it is a space and then restarts.
If you want to convert everything to lowercase and then examine it again you'll need to write two loops.
> I have figured out a way to fix the error!

There is an off-by-one error in the loop; you need to fix that too.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
std::string convert_song( std::string songname )
{
    if( !songname.empty() )
    {
         // convert the first char to upper case if it is lower case
         songname[0] = std::toupper( songname[0] ) ;

         // iterate till songname[i] is the second last char (songname[i+1] is the last char)
         for( std::size_t i = 0 ; i < songname.size() - 1 ; ++i )
         {
             if( std::isspace( songname[i] ) ) songname[i+1] = std::toupper( songname[i+1] ) ;
             else songname[i+1] = std::tolower( songname[i+1] ) ;
         }
    }

    return songname ;
}
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
#include <iostream>
#include <string>
#include <algorithm>

int main()
{
	std::string s( "   sOmE  nAmE " );

	std::cout << '\"' << s << '"' << std::endl;


	bool bPrevBlank = true;

	std::transform( s.begin(), s.end(), s.begin(),
		[&bPrevBlank]( char c ) -> char
		{
			bool bCurrentBlank = std::isspace( c );
			if ( !bCurrentBlank )
			{
				c = bPrevBlank ? std::toupper( c ) : std::tolower( c );
			}
			bPrevBlank = bCurrentBlank;
			return ( c );
		} );

	std::cout << '\"' << s << '"' << std::endl;
}
Last edited on
If to call std::toupper or std::tolower even for a white space character then the body of the lambda expression can be rewritten simpler

1
2
3
4
5
{
	c = bPrevBlank ? std::toupper( c ) : std::tolower( c );
	bPrevBlank = std::isspace( c );
	return ( c );
}
If to use ordinary loops then the function could look the following way

1
2
3
4
5
6
7
8
9
10
11
12
std::string & convert_song( std::string &songname )
{
    bool bPrevBlank = true;

    for ( char &c : songname )
    {
        c = bPrevBlank ? std::toupper( c ) : std::tolower( c );
        bPrevBlank = std::isspace( c );
    }

    return songname ;
}
Topic archived. No new replies allowed.