I am having trouble converting a string, stored as input, to all lower case.....and save the lower case in a string, search. perhaps my idea is flawed?

search = tolower(input);

Recommended Answers

All 7 Replies

tolower() only works on a per char basis, see the man page here.

http://linux.die.net/man/3/tolower

True :)

Try something like this:

void conv2lower(string &s) {
     for(unsigned int i = 0; i < s.length(); i++) 
           s[i] = tolower(s[i]);
}

Usage:

string msg = "HELLO WoRLd!!";
conv2lower(msg); // msg contains now the string "hello world!!"
Member Avatar for jencas

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

>std::transform(msg.begin(), msg.end(), msg.begin(), std::tolower);
Congratulations, you've propagated one of the more annoying bugs among C++ help forums[1].

1) tolower isn't just a function in <cctype>, it's also a template in <locale>, which is allowed to be included by any standard header (<iostream> is the usual culprit). As written, there's an ambiguity and the name can't be resolved[2].

2) The usual "fix" is also wrong:

std::transform(msg.begin(), msg.end(), msg.begin(), (int(*)(int))std::tolower);

I consider this a casualty of overly clever programmers trying too hard to retain the one-liner status of this solution. However, it's wrong because tolower expects an integer argument in the range of unsigned char. If vanilla char is signed on your system, you've got problems because plenty of valid negative character values can be promoted to int and fall outside the range of unsigned char. The code will compile but is non-portable at best and undefined at worst.

The correct solution would be some variation of this:

struct uppercase {
    int operator() ( int c ) const
    {
        return std::toupper ( (unsigned char)c );
    }
};

std::transform ( msg.begin(), msg.end(), msg.begin(), uppercase() );

[1] Annoying because it's incredibly subtle, doesn't always exhibit buggy behavior, and everyone and his brother will try to argue its correctness. :icon_rolleyes:
[2] Technically the name can be resolved, as the information is present to do so if the implementer chooses to do the extra work of gathering it, but it's not a standard practice, so you'd be relying on an implementation detail and the code would still be non-portable.

commented: Damn! Do you always have to be so logical :) +36
commented: Thank you for taking the time to spell out the issues with this. +18

nice function...

for the simple needs of my application this is perfect!

Thanks much

>std::transform(msg.begin(), msg.end(), msg.begin(), std::tolower);
Congratulations, you've propagated one of the more annoying bugs among C++ help forums[1].

1) tolower isn't just a function in <cctype>, it's also a template in <locale>, which is allowed to be included by any standard header (<iostream> is the usual culprit). As written, there's an ambiguity and the name can't be resolved[2].

2) The usual "fix" is also wrong:

std::transform(msg.begin(), msg.end(), msg.begin(), (int(*)(int))std::tolower);

I consider this a casualty of overly clever programmers trying too hard to retain the one-liner status of this solution. However, it's wrong because tolower expects an integer argument in the range of unsigned char. If vanilla char is signed on your system, you've got problems because plenty of valid negative character values can be promoted to int and fall outside the range of unsigned char. The code will compile but is non-portable at best and undefined at worst.

The correct solution would be some variation of this:

struct uppercase {
    int operator() ( int c ) const
    {
        return std::toupper ( (unsigned char)c );
    }
};

std::transform ( msg.begin(), msg.end(), msg.begin(), uppercase() );

[1] Annoying because it's incredibly subtle, doesn't always exhibit buggy behavior, and everyone and his brother will try to argue its correctness. :icon_rolleyes:
[2] Technically the name can be resolved, as the information is present to do so if the implementer chooses to do the extra work of gathering it, but it's not a standard practice, so you'd be relying on an implementation detail and the code would still be non-portable.

Narue could you explain the working of the second way of converting. Ie : with the struct uppercase, I dint get it.

>Narue could you explain the working of the second way of
>converting. Ie : with the struct uppercase, I dint get it.
It's a function object. By overloading the function call operator for a class (or struct), you can make it look like a function even though it's an object:

#include <cctype>
#include <iostream>
#include <string>

struct uppercase {
    int operator() ( int c ) const
    {
        return std::toupper ( (unsigned char)c );
    }
};

int main()
{
    uppercase foo;

    std::cout<< (char)foo ( 'a' ) <<'\n';
}

The idea being that an object can do a lot more than a function can, like retain state without error prone tricks. Here's the same transform code with a regular function:

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>

int uppercase ( int c )
{
    return std::toupper ( (unsigned char)c );
}

int main()
{
    std::string foo ( "this is a test" );

    std::cout<< foo <<'\n';
    std::transform ( foo.begin(), foo.end(), foo.begin(), uppercase );
    std::cout<< foo <<'\n';
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.