WSkinner
WSkinner

Reputation: 2217

How to find matching string in a list of strings

I am learning c++ and wondering what the best or most idiomatic way to do the following would be. I have a list of known accepted strings that will be constant for a program. I want to know if a string provided to a function is in the list of my accepted strings. I came up with:

bool match(const char* foo, const char* bar) {
    return strcmp(foo, bar) == 0;
}

bool thingIsValid(const char* thing) {
    return match("foo", thing) || match("bar", thing) || match("baz", thing);
}

...
thingIsValid(someArg.c_str());
...

This approach just seems to be more of the C idiom to me. In other languages I would probably just have a list and do a .contains(thing) on that list. How do people typically do this in C++?

Upvotes: 2

Views: 7556

Answers (4)

Connor Clark
Connor Clark

Reputation: 706

The accepted answer uses a std::vector<std::string> and says it is not ideal to keep this on the heap, but you don't need to use std::vector or std::string. The following should work, and the data will be stored in read only memory.

static auto banned_fnames = {
    "..", ".", "AUX", "COM", "COM2", "COM3", "COM4", "COM5", "COM6",
    "COM7", "COM8", "COM9", "CON", "LPT1", "LPT2", "LPT3", "LPT4",
    "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "NUL", "PRN",
};
auto stem = resolved_path.stem().string();
if (std::find(std::begin(banned_fnames), std::end(banned_fnames), fname) != std::end(banned_fnames))
{
    error = fmt::format("Bad path: {} - banned filename", user_path);
    return "";
}

Upvotes: 0

Peter Ruderman
Peter Ruderman

Reputation: 12485

Probably the best way these days is to use an unordered set:

std::unordered_set<std::string> ValidValues {"one", "two", "three"};

if( ValidValues.find( testString ) == ValidValues.end() ) {
    // String is not valid...
}

The only real disadvantage here is that you can't simply lay out the valid strings in your executable image. (Setting up the set requires initialization code and heap allocations.) But that shouldn't really matter for the vast majority of applications.

Upvotes: 7

One possible way to do it:

bool thingIsValid(const std::string &thing) {
  static const std::vector<std::string> validValues {"foo", "bar", "baz"};
  return std::find(validValues.begin(), validValues.end(), thing) != validValues.end();
}

The above piece of code uses C++11 list-initialisation to create the vector. If you don't have C++11, you would have to construct the vector by using push_back().

Upvotes: 2

Khaur
Khaur

Reputation: 770

std::string::find is what you're looking for. Reference

Upvotes: 1

Related Questions