Using tolower on a string

Pages: 12
Hi guys,

I'm writing a program, which asks questions to the user, who then awnsers them.

When the user awnsers it, I first want my program to lowercase all characters in the awnser, and then do an if-loop.

However, somehow my compiler gives an error, saying that I can't lower strings :S
Could somebody tell me how this could be done? Or maybe how to convert a string into an int or char, so I can lowercase that (or something).

And also, how can you use switch statements with strings?

Thanks in advance! :)

-Kaduuk

Ps here is my code:

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
/* This is a program which poses questions to the user. If the user awnsers something, it'll ask the next question
based on the previous awnser...
The interface is meant to be as if it's some sort of chat
*/
#include <iostream>
#include <string>
#include <windows.h>
using std::cout;
using std::cin;
using std::getline;
using std::tolower;
using std::endl;
using std::string;

int main (int argc, char * argv[])
{
    std::string name;
    cout<<"Program says: Hi, what's your name?"<<endl;  //q for name
    cout<<"User says: ";
    std::getline (cin,name); //get name

    cout<<"Program says: Hi "<<name<<", are you fine?"<<endl; //how are you?
    cout<<"User says: ";
    string ans;
    getline(cin,ans);
    
    if((ans == "yes")||(ans =="Yes")) {cout<<"Program says: That's great! I'm fine to :)"<<endl;}  //if yes say me 2
    else{cout<<"Program says: Don't worry, it'll be allright!"<<endl;} //if no, encourage user

    cout<<"Program says: So tell me, "<<name<< ",do you like today's weather too?"<<endl;
    cout<<"User says: ";
    getline(cin,ans);
    if((ans == "yes")||(ans == "Yes"))
    {cout<<"\nProgram says: Cool!";}

    cout<<"So what kind of weather do you like?\nCloudy, Sunny, Rainy, Windy, Humid or Dry? ";
    string weth;
    getline (cin,weth);
    if(weth == "cloudy"){cout<<"Prgoram says: I guess it's okay if it's cloudy sometimes"<<endl;}
    else if(weth == "sunny"){cout<<"Program says: I love it when it's sunny!"<<endl;}
    else if(weth == "windy")
    {
         cout<<"Program says: I only like that when it's hot.. You too?";
         getline (cin,ans);
         if((ans == "yes")||(ans=="Yes"))
                {cout<<"Great! That's something we have in common then!"<<endl;}
         else {cout<<"Ah well, people differ"<<endl;}
    }
    
           
 return 0;   
}
Last edited on
You will have to use a for loop to loop over the character and use tolower() on each one. tolower() is meant for characters by themselves, not strings.
Ok, so how'd I have to do that? (sorry I'm a real beginner and I haven't had for loops yet)
I'm a beginner too, so I don't quite understand how you have the code set up... I'm confused because there's no initializing of variables, but I've never seen getline(cin,variable) before.

This is the code to convert to lowercase:

1
2
3
4
5
#include <cctype> //I don't if tolower() comes already with <string>
//...
//it will loop through characters until it comes to null terminator,
for (int i=0; ans[i]; i++) ans[i] = tolower(ans[i]);
//... 


It could be more efficient if you'd add if statement to check if a character is already in lowercase. I say "could" because while the program wouldn't change to lowercase every character, it would have to perform if statement on every character.
I don't know which uses more resources, I hope somebody has the answer.
I'm a beginner too, so I don't quite understand how you have the code set up... I'm confused because there's no initializing of variables, but I've never seen getline(cin,variable) before.


@Fresh Grass: It sounds like you have been learning C. Most of the functions etc. he is using are C++ functions. You can use the reference on this site to look them up if you need to.

And as for the check, I don't think it would help much because tolower() already has to check to make sure it is in the uppercase range (I think, I could be wrong)

@OP: Anyway, Fresh Grass' solution would work on a C string, but not on an std::string. If you need help with for loops: http://www.cplusplus.com/doc/tutorial/control/#for
I'm an absolute beginner, so I have big holes in my knowledge. The book I'm learning from (C++ guide by Herbert Schildt) only mentioned cstring (so far).

So how would I transform c++ strings to lowercase? Is it just a different function, or is there more to it?

About the check, I think you're right. Each character has a value and if you want to transform to uppercase, you have to add or remove 32, I think.
So to transform "a" to "A", you'd write "var =+ 32;". That's why there has to be a check, otherwise you'd be adding 32 to already uppercased "A", which would result in some completely different character or error.
I could be wrong again, though :)

So how would I transform c++ strings to lowercase? Is it just a different function, or is there more to it?


You would generally do it something like this:

1
2
3
4
std::string my_string("mY sTrInG");
for(unsigned int i = 0; i < my_string.length(); ++i) {
    my_string[i] = tolower(my_string[i]);
}


The basic stuff is the same except an std::string knows it's length so you don't need a NULL char at the end or a size value.

Although if you can use boost then it becomes 1 line.

boost::algorithm::string::to_lower(my_string);
I see, so basically when you initialize a string this way: "string answer;", it is automatically considered an array, right?
I have one other question - I have seen that sometimes main function is written with parameters, such as:

int main (int argc, char * argv[])

What does that actually do?
Fresh Grass wrote:
So how would I transform c++ strings to lowercase? Is it just a different function, or is there more to it?


You could always use std::transform!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

int main()
{
	std::string word = "All Over The Case";

	std::transform(word.begin(), word.end(), word.begin(), tolower);

	std::cout << word << std::endl;

	return 0;
}
Last edited on
I see, so basically when you initialize a string this way: "string answer;", it is automatically considered an array, right?

No, std::string is just overloading operator[].

I have one other question - I have seen that sometimes main function is written with parameters, such as:

int main (int argc, char * argv[])

What does that actually do?

In that form, any parameters that the program was started with will be passed in these arguments.
argc denotes how many elements the C string array argv contains and argv contains the actual parameters (first always being the program name).
Last edited on
Ok thanks guys!

And I have one more little offtopic question: do voids always have to be placed before main or not?
And how could you write a switch statement with a string?


Edit: Ok this is weird. If I make a similar different program, it works fine. However, if I make a void, containing almost the same code I made for the different program, it doesnt work correctly :S

1
2
3
4
5
6
7
8
void Lower_Ans()
{
     std::string ans;
     for(unsigned int i = 0; i < ans.length(); ++i) {
                  ans[i] = tolower(ans[i]);
                  }
}


and

1
2
3
4
5
void Lower_Ans()
{
    std::string ans;
    std::transform(ans.begin(), ans.end(), ans.begin(), tolower);
}


Both dont work :S

In the first Lower_Ans() I tried assigning the ans string to itself ( so std::strin ans(ans) ) which makes the program crash (after thinking over it it's obvious to me why)

And in the second Lower_Ans() I tried adding another bracket after tolower (thinking that made the difference, because my compiler stated there was one missing), however, after doing so, it automatically opens the cctype.h file, and states there is an error in there (which I don't understand)

Please bear with me guys..

Cheers!

-Kaduuk
Last edited on
There should never be a void before your main function. It should always be an int and it should always be there:

1
2
3
4
int main()
{
    return 0;
}


You can not write a switch statement using a string.
Last edited on
@ Galik:

I didn't mean to make the main a void, but something like void Lower_Ans() , or just some other void (not main)

But is there another way of writing a switch statement based on a user-input string (converting the string to a char or int?)
Every function requires a return type. If there is no return value then the type must be specified as void.

By the time you have converted your string to a char or an int you have probably done as much work as the normal if() block testing that you are trying to avoid.

I would just bite the bullet and write the if() blocks rather than convert and then switch().
Sorry, I missed this before:

1
2
3
4
void Lower_Ans(std::string& ans) // remember to pass by reference &
{
    std::transform(ans.begin(), ans.end(), ans.begin(), tolower);
}


That should work.

EDIT:

Ahh, now I see where your question about the void comes in... hehe:

1
2
3
4
5
std::string Lower_Ans(std::string word)
{
	std::transform(word.begin(), word.end(), word.begin(), tolower);
	return word;
}


Is that what you were after?
Last edited on
Turning strings into chars or ints doesn't make much sense unless the string is one character long. if, else if and else will just have to suffice. I can think of some more elaborate solutions but I suspect they'd simply be overkill/too much effort for what you intend to do.
Last edited on
My compiler somehow can't handle the transform :S

It says :

no matching function for call to `transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unknown type>)'


And I dont see how the
1
2
3
4
5
std::string Lower_Ans(std::string word)
{
	std::transform(word.begin(), word.end(), word.begin(), tolower);
	return word;
}

should be fitted in.. It's not a function (right?) so it can't return a value. (that's also what my compiler states)
And when I make a void out of it, it states that a void can't return a value :S

I think we're almost there :)
You need these headers:

1
2
3
#include <string>
#include <algorithm>
#include <cctype> 


And it is a function. So it has a return value if you want it. What did you think it was if not a function?
I've already included those... And I thought it was a function, but my compiler says it isn't (and thus can't compile it) :S
From the error message it looks like it can't find your tolower() function. Is your #include <windows.h> interfering with it maybe? Try reversing the order in which you include <windows.h> and <cctype>.

Else you could try prefixing tolower with ::

1
2
3
4
5
std::string Lower_Ans(std::string word)
{
	std::transform(word.begin(), word.end(), word.begin(), ::tolower); // scope resolution operator ::
	return word;
}
Pages: 12