Check if input string has leading or trailing whitespaces in C++?

Viewed 418

I am trying to validate a single-line input string in C++11 to see if it contains any leading / trailing whitespaces. My code now looks like this:

bool is_valid(const std::string& s) {
    auto start = s.begin();
    auto end = s.end();
    if (std::isspace(*start) || std::isspace(*end)) {
        return false;
    } 
    return true;
}

int main() {
    std::string name{};
    std::getline(std::cin, name);
    if (!is_valid(name)) {
        std::cout << "Invalid!";
    }
    return 0;
}

But now the program can only detect leading whitespaces. For example, for John it would print Invalid! but for Mary it would classify it as valid input, which is not. Does anyone know what's wrong with my program?

5 Answers

A simple test for std::string::front() and std::string::back() could have been done after testing for the empty string:

bool is_valid(const std::string& s) 
{
   return s.empty() || 
    (!std::isspace(static_cast<unsigned char>(s.front())) && 
     !std::isspace(static_cast<unsigned char>(s.back())));
}

The end iterator does not point to an element in the container. It points one past the last element. You may not dereference the end iterator. For a std::string you can use it's operator[]:

char last_char = s[s.size()-1];

advance the begin iterator:

auto it = s.begin() + s.size()-1;
char last_char = *it; 

or decrement the end iterator:

auto it = s.end() -1;
char last_char = *it;

Other alternatives are back() or using the reverse iterator rbegin().

Note that they all require s.size() != 0. For an empty string s.begin() == s.end(). You should check that first in the function and return true for that case.

s.end() is one pass the end of the string just like any other containers in C++, so accessing it invokes undefined behavior. You need to use std::prev(s.end()) instead (which is valid only the string contains at least 1 character though, so you need to check the string length first)

Yes, .end() is to the past-the-end element. Then why not using .back() instead?

bool is_valid(std::string const& str) {
    return str.empty() || !(std::isspace(str.front()) || std::isspace(str.back()));
}
Related