How it works...

For implementing the utility functions from the library, we have two options:

  • Functions would modify a string passed by a reference.
  • Functions would not alter the original string but return a new string.

The second option has the advantage that it preserves the original string, which may be helpful in many cases. Otherwise, in those cases, you would first have to make a copy of the string and alter the copy. The implementation provided in this recipe takes the second approach.

The first functions we implemented in the How to do it... section were to_upper() and to_lower(). These functions change the content of a string either to uppercase or lowercase. The simplest way to implement this is using the std::transform() standard algorithm. This is a general purpose algorithm that applies a function to every element of a range (defined by a begin and end iterator) and stores the result in another range for which only the begin iterator needs to be specified. The output range can be the same as the input range, which is exactly what we did to transform the string. The applied function is toupper() or tolower():

    auto ut{ string_library::to_upper("this is not UPPERCASE"s) };  
// ut = "THIS IS NOT UPPERCASE"

auto lt{ string_library::to_lower("THIS IS NOT lowercase"s) };
// lt = "this is not lowercase"

The next function we considered was reverse(), that, as the name implies, reverses the content of a string. For this, we used the std::reverse() standard algorithm. This general purpose algorithm reverses the elements of a range defined by a begin and end iterator:

    auto rt{string_library::reverse("cookbook"s)}; // rt = "koobkooc"

When it comes to trimming, a string can be trimmed at the beginning, end, or both sides. Because of that, we implemented three different functions: trim() for trimming at both ends, trimleft() for trimming at the beginning of a string, and trimright() for trimming at the end of a string. The first version of the functions trims only spaces. In order to find the right part to trim, we use the find_first_not_of() and find_last_not_of() methods of std::basic_string. These return the first and last characters in the string that are not the specified character. Subsequently, a call to the substr() method of std::basic_string returns a new string. The substr() method takes an index in the string and a number of elements to copy to the new string:

    auto text1{"   this is an example   "s}; 
// t1 = "this is an example"
auto t1{ string_library::trim(text1) };
// t2 = "this is an example "
auto t2{ string_library::trimleft(text1) };
// t3 = " this is an example"
auto t3{ string_library::trimright(text1) };

It could be sometimes useful to trim other characters and then spaces from a string. In order to do that, we provided overloads for the trimming functions that specify a set of characters to be removed. That set is also specified as a string. The implementation is very similar to the previous one because both find_first_not_of() and find_last_not_of() have overloads that take a string containing the characters to be excluded from the search:

    auto chars1{" !%

"s}; 
auto text3{"!! this % needs a lot of trimming ! "s};
auto t7{ string_library::trim(text3, chars1) };
// t7 = "this % needs a lot of trimming"
auto t8{ string_library::trimleft(text3, chars1) };
// t8 = "this % needs a lot of trimming ! "
auto t9{ string_library::trimright(text3, chars1) };
// t9 = "!! this % needs a lot of trimming"

If removing characters from any part of the string is necessary, the trimming methods are not helpful because they only treat a contiguous sequence of characters at the start and end of a string. For that, however, we implemented a simple remove() method. This uses the std:remove_if() standard algorithm. Both std::remove() and std::remove_if() work in a way that may not be very intuitive at first. They remove elements that satisfy the criteria from a range defined by a first and last iterator by rearranging the content of the range (using move assignment). The elements that need to be removed are placed at the end of the range, and the function returns an iterator to the first element in the range that represents the removed elements. This iterator basically defines the new end of the range that was modified. If no element was removed, the returned iterator is the end iterator of the original range. The value of this returned iterator is then used to call the std::basic_string::erase() method that actually erases the content of the string defined by two iterators. The two iterators in our case are the iterator returned by std::remove_if() and the end of the string:

    auto text4{"must remove all * from text**"s}; 
auto t10{ string_library::remove(text4, '*') };
// t10 = "must remove all from text"
auto t11{ string_library::remove(text4, '!') };
// t11 = "must remove all * from text**"

The last method we implemented splits the content of a string based on a specified delimiter. There are various ways to implement this. In this implementation, we used std::getline(). This function reads characters from an input stream until a specified delimiter is found and places the characters in a string. Before starting to read from the input buffer, it calls erase() on the output string to clear its content. Calling this method in a loop produces tokens that are placed in a vector. In our implementation, empty tokens were skipped from the result set:

    auto text5{"this text will be split   "s}; 
auto tokens1{ string_library::split(text5, ' ') };
// tokens1 = {"this", "text", "will", "be", "split"}
auto tokens2{ string_library::split(""s, ' ') };
// tokens2 = {}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset