2

Say I have an input that is stored in a char c, and in a conditional I need to check whether it is either of two different characters, for example 'n' and 'N'. It's obvious that I can make a conditional with a logical OR operator:

if(c == 'n' || c == 'N')
...

However, if there are significantly more than just two conditions, than that will require significantly more logical operators to be used, and it will become tedious to write, look at, and edit. Is there a way to condense this process? To make it look like something along the lines of this:

if(c == '[N][n]')
...

Does anything of the sort exist?

Daniel
  • 509
  • 1
  • 4
  • 17

3 Answers3

9

You can make a string of your matching characters and see if the character in question exists in the string:

char c;
std::string good_chars = "nNyYq";
if(good_chars.find(c) != std::string::npos) {
    std::cout << "it's good!";
}
scohe001
  • 15,110
  • 2
  • 31
  • 51
  • An O(N) solution to an O(1) problem. Are you in the hardware leasing business? – Bathsheba Mar 16 '18 at 19:38
  • 1
    @Bathsheba `O(n)`? What's `n` in this case to you? It looks to me like everything is constant... – scohe001 Mar 29 '18 at 20:39
  • find is an O(N) traversal. – Bathsheba Mar 30 '18 at 07:06
  • @Bathsheba I suppose that if you're talking about my solution to the problem "Find if a character is in the set of N good characters" you'd be right that it's `O(n)`, but once he implements this, that `n` is a constant (unless the set of good chars is changing at runtime, but that's not specified). Remember that even `for(int i=0; i < 999999; i++) { }` is O(1)... – scohe001 Apr 02 '18 at 19:11
5

A low-tech solution would be to use a switch statement instead. Reading and editing may turn out to be much easier with case labels if you have a lot of matching characters.

bool matches(char c)
{
    switch (c)
    {
        case 'n':
        case 'N':
        case 'a':
        case 'b':
        case 'c':
        return true;
    }
    return false;
}

A more advanced solution would be to store the characters in a container. std::set would be an option:

bool matches(char c)
{
    // note: might want to use static storage for `chars`
    std::set<char> const chars =
    {
        'n',
        'N',
        'a',
        'b',
        'c',
    };
    return chars.find(c) != end(chars);
}

std::string allows for a more condensed form, which may be good or bad as far as readability and maintainability is concerned:

bool matches(char c)
{
    // note: might want to use static storage for `chars`
    std::string const chars = "nNabc";
    return chars.find(c) != std::string::npos;
}

Note that different containers have different algorithmic complexity characteristics, which may be relevant if a function like match should actually turn out to be a performance bottleneck.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • You ought to note that, in order of your presentation, the approaches are O(1), O(log N), then O(N). – Bathsheba Mar 16 '18 at 19:37
  • Is a switch really O(1)? I'd expect the worst case to still be an O(n) test until you match – user4581301 Mar 16 '18 at 19:45
  • @Bathsheba: I'm not sure if that's not bordering on premature optimisation. The OP's question was mainly about code becoming *"tedious to write, look at, and edit"*. However, I'll add a note about the container choice having an impact on algorithmic complexity. – Christian Hackl Mar 16 '18 at 19:48
1

You can use to_upper or to_lower APIs if your scanning is not case sensitive this way:

char c = 'n';
if( static_cast<unsigned char>('N') == std::toupper(static_cast<unsigned char>(c)) )
    // do something

Or:

char c = 'n';
if( static_cast<unsigned char>('n') == std::tolower(static_cast<unsigned char>(c)) )
    // Do something
Raindrop7
  • 3,889
  • 3
  • 16
  • 27