String Manipulation Made Easy with std::string Algorithms

String Manipulation Made Easy with std::string Algorithms

ext processors, spellcheckers, and IDEs are just a few classic examples of applications that need to manipulate strings extensively. Web-oriented applications also make heavy use of strings for generating text, processing clients’ requests, processing scripts, and logging. Clearly, string-savviness is becoming an important skill in many programming areas. In the following sections, learn how to implement some common string-oriented tasks using std::string and its member functions.

How can you perform case-insensitive comparisons and find and replace operations with string objects?

Use the specialized algorithms of class std::string.

Case Insensitive Comparisons
The overloaded == operator of std::string performs a case-sensitive lexicographical comparison. This feature is useful in implementing IDEs of case-sensitive programming languages such as C++. However, there are situations in which you need a case-insensitive comparison. Suppose you need to locate all of the occurrences of a certain word in a document:

string Evita_lyrics  ="Mourning all day and mourning all night";

A common technique for eliminating case differences is transforming the entire string to uppercase letters. However, this approach is ruled out if the original string must remain intact. Alternatively, you can let the comparison function locally convert each letter to its uppercase counterpart as shown in the following code listing:

int nocase_cmp(const string & s1, const string& s2) {  string::const_iterator it1=s1.begin();  string::const_iterator it2=s2.begin();  //stop when either string's end has been reached  while ( (it1!=s1.end()) && (it2!=s2.end()) )   {     if(::toupper(*it1) != ::toupper(*it2)) //letters differ?     // return -1 to indicate smaller than, 1 otherwise      return (::toupper(*it1)  < ::toupper(*it2)) ? -1 : 1;     //proceed to the next character in each string    ++it1;    ++it2;  }  size_t size1=s1.size(), size2=s2.size();// cache lengths   //return -1,0 or 1 according to strings' lengths    if (size1==size2)       return 0;    return (size1

Test this function:

string s1="Mourning";string s2="mourning";int n=nocase_cmp(s1, s2); //n=0

As expected, the result is 0 indicating that the strings are identical is spite of the case difference of their initial letter.

Author's Note: Don't be tempted to hide the nocase_cmp() function in an overloaded == as this will clash with the standard (and case-sensitive) == operator.

Searching a Substring Within a String
Searching a substring within a string is another common task in text-oriented apps. The Standard Library defines several specialized overloaded versions of string::find(). These overloaded versions take const string&, const char *, or char as a sought-after value. For the sake of brevity, I will focus only on locating a string object within another string object:

string phrase="Franco's rain in Spain";string sought = "rain";int pos=phrase.find(sought); // pos=9

find() returns the position of sought's first character within phrase. This position can then be used for further manipulations such as deleting the sought-after string or replacing it with another value. Test if the search succeeded like this:

if(pos!= string::npos) //successelse   //not found

If the sought-after string wasn't found, find() will return string::npos, which is an agreed-upon constant value indicating an invalid position in any string.

Figure 1: Replacing a Substring.

Replacing a Substring
To replace the sought-after value, use the replace() function which also has several overloaded versions. Again, use the canonical version which takes three arguments: the position to which the replacement string should be written, the length of the substring to be replaced, and an overriding string. For example, the following snippet corrects a typo in phrase by replacing 'rain' with 'reign':

phrase.replace(pos, sought.size(), replacement); cout<

Figure 1 shows what the output looks like.

In fact, the search and replace operations can be combined into a single statement:

phrase.replace(phrase.find(sought),                sought.size(),                replacement);

Remember that this form should be used only when you're certain that the sought-after value exists in the containing string (this may be the case if the processed sentence is machine-generated, for example). If there's no such guarantee, check whether the search operation succeeded before calling replace().

Figure 2: replace() automatically adjusts its object's capacity to fit to its new size.

Superb Strings
I silently ignored an issue that may have perturbed you: 'reign' is one character longer than the replaced value 'rain' and yet the program didn't extend the original string's size before calling replace(). Is this an oversight? No, it isn't. replace() automatically adjusts its object's capacity to fit to its new size. To convince the skeptics among you, I'll use a longer replacement string and check the string object's capacity before and after the replace() call:

cout<<"original string capacity: "<

As you can see, the resulting string and its capacity were expanded automatically:

And that, my friends, is the beauty of std::string!


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist