0

I am asking a user to enter their name and I want to automatically format the name so that, no matter how they enter the name, it will appear as capital first letter, lower case the rest. For example, if they enter "joHN" the program will still output their name as "John."

I have the following code for their name input:

string name;
cout << "Please enter your first name: ";
cin >> name;

I am assuming I will have to use the toupper and tolower commands, but I am really unsure how to write something to adjust each character in the string.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
user2999339
  • 11
  • 1
  • 1
  • 3
  • Only a comment for most answerers: I think to suggest an STL algorithm based on iterators and other C++ machinery is not a good answer for somebody who is asking about upper/lower functions. He/she is a C++ newbbie. Thats why I have not mentioned `std::transform()`, which is the most elegant solution so far. – Manu343726 Nov 16 '13 at 13:36
  • @Manu343726, true, but not everyone that comes here will be a complete "newbie". – Paul Draper Nov 17 '13 at 10:06

4 Answers4

6

The Standard Library provides the C functions std::toupper() and std::tolower() which return the upper/lower case of the specified ASCII character. So your problem could be solved with a simple for loop:

if( !name.empty() )
{
    name[0] = std::toupper( name[0] );

    for( std::size_t i = 1 ; i < name.length() ; ++i )
        name[i] = std::tolower( name[i] );
}
Manu343726
  • 13,969
  • 4
  • 40
  • 75
  • `!name.empty()` is more efficient than `name.size() > 0` – Alexander Oh Nov 16 '13 at 13:32
  • @Alex. Thanks. We are refinning the answer bit a bit. This seems like a wiki :) – Manu343726 Nov 16 '13 at 13:33
  • There are also the equivalent C++ standard functions [`std::toupper`](http://en.cppreference.com/w/cpp/locale/toupper) and [`std::tolower`](http://en.cppreference.com/w/cpp/locale/tolower) which are wrappers around the respective methods of the [`std::ctype`](http://en.cppreference.com/w/cpp/locale/ctype) facet. – David G Nov 16 '13 at 13:46
  • When I try this I am given the error "'length' undeclared (first use this function)." I tried searching this but came up empty. Is this because I haven't assigned a max length value to string name? – user2999339 Nov 16 '13 at 13:53
  • @user2999339 [`std::string::length()`](http://es.cppreference.com/w/cpp/string/basic_string/size) is a member function of `std::string`. There is no reason because it does not work, except you are not using `std::string`. – Manu343726 Nov 16 '13 at 13:55
  • @Manu343726 I am using #include , , and . Is this what you meant? You are right that I am completely new to this, so please forgive me if I'm missing what you're saying. – user2999339 Nov 16 '13 at 14:01
  • @user2999339 yes, thats what I mean. So your includes are correct and you are using `std::string`. As I said before, there is no reason wich explains why `length()` does not work. Could you provide the exactly compiler error? – Manu343726 Nov 16 '13 at 14:02
  • @Manu343726 ` Program.cpp: In function 'int main()': Program.cpp:25: error: 'length' undeclared (first use this function) Program.cpp:25: error: (Each undeclared identifier is reported only once for each function it appears in.) make.exe: *** [Program.o] Error 1'code'` – user2999339 Nov 16 '13 at 14:10
  • @Manu343726 when I changed "length" to "name.length" it worked perfectly. Thank you for the help. – user2999339 Nov 16 '13 at 14:21
  • @user2999339 sorry, was my fault :( – Manu343726 Nov 16 '13 at 16:23
5

The simplest solution is probably to make the whole word lower-case first, then make the first character upper case.

C++ has some nice algorithms in the standard library. For this I suggest std::transform together with std::tolower. And there's of course std::toupper for the last part:

if (!name.empty())
{
    std::transform(std::begin(name), std::end(name), std::begin(name),
                   [](char const& c)
                   {
                      return std::tolower(c);
                   });

    name[0] = std::toupper(name[0]);
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Please wrap `std::tolower` into a lambda, as cppreference suggested. See https://stackoverflow.com/q/55687044/5376789. – xskxzr Aug 06 '21 at 02:40
2

Assume there is no spaces at the beginning, you can use std::toupper() and std::tolower():

for (size_t i = 0; i < name.length(); i++)
    name[i] = i==0? std::toupper(name[i]) : std::tolower(name[i]);

More efficient by longer code:

if (name.length()>0)
{
    name[0] = std::toupper(name[0]) ;
    for (size_t i = 1; i < name.length(); i++)
        name[i] = std::tolower(name[i]);
}

And finally, this code skips first spaces (if exists)

std::string capital(std::string name)
{
    if (!name.empty())
    {
        auto i = name.begin();

        while (i != name.end() && std::isspace(*i))
            ++i;

        if (i == name.end())
            return name;

        *i = std::toupper(*i++);

        std::transform(i, name.end(), i, ::tolower);
    }

    return name;
}
masoud
  • 55,379
  • 16
  • 141
  • 208
2

An other fast solution

#include <algorithm>
#include <string> 

if (!name.empty()) // Edit : Add the verification
{
   std::transform(name.begin(), name.end(), name.begin(), ::tolower);
   name[0] = std::toupper(name[0]);
}
jbouny
  • 351
  • 2
  • 9