Strings and String Manipulation in C++
Carlos Moreno

Copyright © 2000-2001

 
C++ provides convenient and powerful tools to manipulate strings. This tutorial shows some of the basic string manipulation facilities, with examples to illustrate their use. 

In C++, strings are not a built-in data type, but rather a Standard Library facility.  Thus, whenever we want to use strings or string manipulation tools, we must provide the appropriate #include directive, as shown below:

    #include <string>
    using namespace std;

The using namespace std directive is not the only way to obtain access to the string facilities, but it is the simplest, so I will stick to it in this tutorial.

C++ strings allow you to directly initialize, assign, compare, and reassign with the intuitive operators, as well as printing and reading (e.g., from the user), as shown in the example below:

    string name;
    cin >> name;
       // read string until the next separator
       // (space, tab, newline)

    getline (cin, name);
       // read a whole line into the string name

    if (name == "")
    {
        cout << "You entered an empty string, "
             << "assigning default\n";
        name = "John";
    }

C++ strings also provide many string manipulation facilities.  The simplest string manipulation that we commonly use is concatenation, or addition of strings. In C++, we can use the + operator to concatenate (or "add") two strings, as shown in the example below:

    string result;
    string s1 = "hello ";
    string s2 = "world";
    result = s1 + s2;
        // result now contains "hello world"

Notice that neither s1 nor s2 are modified! The operation reads the values and produces a result corresponding to the concatenated strings, but doesn't modify the two original strings.

The += operator can also be used. In that case, one string is appended to another one, as shown in the following example:

    string result;
    string s1 = "hello";
       // without the extra space at the end
    string s2 = "world";
    result = s1;
    result += ' ';
       // append a space at the end
    result += s2;

Now, result contains the string "hello world".

You can also use two or more + operators to concatenate several (more than 2) strings. The following example shows how to create a string that contains the full name from first name and last name (e.g., firsname = "John", lastname = "Smith", fullname = "Smith, John"):

    #include <iostream>
    #include <string>
    using namespace std;

    int main()
    {
        string firstname, lastname, fullname;

        cout << "First name: ";
        getline (cin, firstname);
        cout << "Last name: ";
        getline (cin, lastname);

        fullname = lastname + ", " + firstname;
        cout << "Fullname: " << fullname << endl;
        return 0;
    }

Of course, we didn't need to do that; we could have printed it with several << operators to concatenate to the output. The example intends to illustrate the use of strings concatenation in situations where you need to store the fullname, as opposed to simply print it.

Now, let's review this example to have the full name in format "SMITH, John". Since we can only convert characters to upper case, and not strings, we have to handle the string one character at a time. To do that, we use the square brackets, as if we were dealing with an array of characters, or a vector of characters.

For example, we could convert the first character of a string to upper case with the following code:

    str[0] = toupper (str[0]);

If we want to change all of them, we would need to know the length of the string.  To this end, strings have a method length(), that tells us the length of the string (how many characters the string has).

Thus, we could use that method to control a loop that allows us to convert all the characters to upper case:

    for (int i = 0; i < str.length(); i++)
    {
        str[i] = toupper (str[i]);
    }

Notice that the subscripts for the individual characters of a string start at zero, and go from 0 to length-1.

The example of the full name is slightly different from the one shown above, since we only want to change the first portion, corresponding to the last name, and we don't want to change the string that holds the last name -- only the portion of the full name corresponding to the last name.  Thus, we could do the following:

    fullname = lastname + ", " + firstname;

    for (int i = 0; i < lastname.length(); i++)
    {
        fullname[i] = toupper (fullname[i]);
    }

Another useful tool for string manipulation is the find method. This can be used to find the position of a character in a string, or the position of a substring. For example, we could find the position of the first space in a string as follows:

    position = str.find (' ');

If the string does not contain any space characters, the result of the find method will be the value string::npos.  The example below illustrates the use of string::npos combined with the find method:

    if (str.find (' ') != string::npos)
    {
        cout << "Contains at least one space!" << endl;
    }
    else
    {
        cout << "Does not contain any spaces!" << endl;
    }

the find method can also be used to find a substring; the following fragment of code can be used to determine if the word "the" is contained in a given string:

    string text;
    getline (cin, text);

    if (text.find ("the") != string::npos)
    {
       ...

Also, you can specify a starting position for the search; in that case, the find method will tell the position of the first occurence of the search string or character after the position indicated.

The following example shows how to test if a string contains at least two spaces. It performs one search for a space, and then it does a second search, starting at the position where the first one was found (actually, one element after -- can you see why?):

    string text;
    getline (cin, text);
    int position = text.find (' ');
 

    if (position != string::npos)
    {
        if (text.find (' ', position+1) != string::npos)
        {
            cout << "Contains at least two spaces!" << endl;
        }
        else
        {
            cout << "Contains less than two spaces!" << endl;
        }
    }
    else
    {
        cout << "Contains no spaces!" << endl;
    }

(there is a minor bug in the above program -- can you see it? even more fun: can you fix it?)

There are several other string facilities that are related to find. Two of them are find_first_of, and find_first_not_of. Instead of finding the first occurrence of an exact string (as find does), find_first_of finds the first occurrence of any of the characters included in a specified string, and find_first_not_of finds the first occurrence of a character that is not any of the characters included in the specified string. An example of use is shown below:

    string text;
    getline (cin, text);

    if (text.find_first_of ("aeiouAEIOU") == string::npos)
    {
        cout << "The text entered does not contain vowels!" 
             << endl;
    }

In this case the expression text.find_first_of ("aeiouAEIOU") returns the position of the first occurrence of any of the characters included in the string passed as parameter -- a string containing all the vowels. find_first_of, like find, returns the position, or string::npos if no character matching the specified requirement was found. In this example, if find_first_of returns string::npos, that means that the string did not contain any vowel (lowercase or capital).

find_first_not_of works in a similar way, except that it finds the first character that is not one of the characters specified in the string, as shown in the example below:

    string SIN;
    cout << "Enter Social Insurance Number: ";
    getline (cin, SIN);

    if (SIN.find_first_not_of ("1234567890- ") != string::npos)
    {
        cout << "The SIN entered contains invalid characters" 
             << endl;
    }

Like find, both find_first_of and find_first_not_of accept also an extra parameter indicating the position where to start the search (naturally, if the parameter is omitted, the search starts at position 0).

We can extract one portion of a string with the method substr(). This does not remove the portion from the original string; instead, it creates a new string that contains the specified portion of the original string. The required substring is specified by the starting position and the number of characters. The following example assigns the variable fragment with the sequence of 5 characters starting at position 6 of the variable text.

    string text = "hello world, this is a test";
    string fragment = text.substr (6, 5);
        // start at 6, take 5 characters

The variable fragment will contain the string "world", and the variable text remains unchanged. 

If we omit the second parameter, then substr() will return a substring starting at the specified position and taking all of the characters after that one. For example:

    string text = "hello world";
    string subs = text.substr (3);

assigns the string "lo world" into the variable subs.
 

 
Copyright © 2000, by Carlos Moreno / Mochima Software/AudioSystems