C++ multiple strings inside an if statement

北城余情 提交于 2019-11-28 02:02:48

You cannot compare a variable against multiple values like that in C++ you should be doing:

if (theString == "Seven" || theString == "seven" || theString ==  "7")
 {
   theInt = 7;
   cout << "You chose: " << theInt << endl;
 }
else if (theString == "Six" || theString == "six" || theString == "6")
 {
   theInt = 6;
   cout << "You chose: " << theInt << endl;
 }

I suppose that the type of the variable theString is std::string. Otherwise at least this comparison

theString == "Seven"

does not make sense,

The condition in the if statement

if (theString == "Seven" || "seven" || "7")

is equivalent to

if ( ( theString == "Seven" ) || ( "seven" ) || ( "7" ) )

and always yields true because at least the address of the string literal "seven" is not equal to zero. So this subexpression ( "seven" ) provides that the whole expression will be equal to true.

You should write

if (theString == "Seven" || theString == "seven" || theString == "7")

But it would be better at first to convert the string to upper or lower case.

For example

#include <algorithm>
#include <string>
#include <cstring>

//...

std::transform(theString.begin(), theString.end(), theString.begin(),
    [](char c) { return std::toupper((unsigned char)c);  });

if (theString == "SEVEN" || theString == "7")
{
    theInt = 7;
    cout << "You chose: " << theInt << endl;
}
else if ( theString == "SIX" || theString == "6" )
{
    theInt = 6;
    cout << "You chose: " << theInt << endl;
}

Using std::set and c++11 you can do one liner with similar syntax as your.

check this:

#include <iostream>
#include <string>
#include <set>

int main()
{

  if( (std::set<std::string>{"Seven", "seven", "7"}).count("seven") )
  {
      std::cout << "foo\n";
  }

  std::string theString("6");

  if( (std::set<std::string>{"Six", "six", "6"}).count(theString) )
  {
      std::cout << "bar\n";
  }
}

update 2017-04-22 -- added code example below


This is a classic example of identifying a derived requirement found during implementation. I suggest you consider writing a function to support it.

change from

if (theString == "Seven" || "seven" || "7")
{
//....

(which is not valid c++ because the if condition is always true)

change to

if (0 == compare(theString, "Seven", "seven", "7")
{
//....

and declare and implement something like

// return 0 when theString matches at least one patX
// else return -1
int compare(const std::string& theString, 
            const char* pat0,  // no default, must provide
            const char* pat1 = nullptr, 
            const char* pat2 = nullptr, 
            const char* pat3 = nullptr, 
            const char* pat4 = nullptr
            /* add as many patX as you desire */)
{
    if (0 == theString.compare(pat0)) return 0; // found a match
    //
    // ignore nullptr patterns 
    if (nullptr != pat1) && (0 == theString.compare(pat1)) {
       return(0);
    }

    if(nullptr != pat2) && (0 == theString.compare(pat2)) {
       return(0);
    }
    // ...

    // when get to end with no match
    return (-1); // indicate no match to any of patterns
}

I actually prefer the following. The above is somewhat like strstr(), where this uses more functionality of std::string

int compare(const std::string& theString, // what you are given
            const std::string& patterns)  // concatenated list of search patterns
{
//.. 
}

This you invoke as

if (0 == compare(theString, "Seven seven SEVEN 7") 
{
// 

The implementation must tease apart space delimited patterns .. but this is not difficult, and can easily be implemented in a loop, so no limit to how many comparisons you wish to test.


When should you consider creating a new function in support of a new derived rerquirement?

It is my practice to create the new function when I can identify 3 or more uses. Good luck.


update 2017-04-22

Found some code I wrote a few years ago, fixed it up, added demos ...

Code compiles and seems to run, but very little testing.

  • I created minimal packaging -- a dummy namepace (dtb - for d___'s tool box), and a dumy class (T471_t - test 471)

dtb::T471_t provides private methods for your review.

  • size_t compare(const std::string s, std::string patterns)

  • size_t grep(const std::string pfn, const std::string patterns, std::ostream& an_ostream = std::cout)

    -- uses compare()

  • size_t cpuinfoGet()

    -- uses grep

    -- "wc < /proc/cpuinfo" (a 'well known file' on ubuntu) reports 54 lines on my 2 core machine, more cores, more lines

  • size_t coreCountGet()

    -- uses grep()

    -- creates nullDev to suppress grep normal output


#include <chrono>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <cassert>

// 'compressed' chrono access --------------vvvvvvv
typedef std::chrono::high_resolution_clock  HRClk_t; // std-chrono-hi-res-clk
typedef HRClk_t::time_point                 Time_t;  // std-chrono-hi-res-clk-time-point
typedef std::chrono::microseconds           US_t;    // std-chrono-microseconds
using   namespace std::chrono_literals;   // support suffixes like 100ms

// examples:
//
//   Time_t start_us = HRClk_t::now();
//
//   auto  duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
//   auto     count_us = duration_us.count();
//   or
//   std::cout << "  complete " << duration_us.count() << " us" << std::endl;

namespace dtb
{
   class T471_t
   {
      const std::string dashLine = ("  --------------------------------------------------------------");
   public:

      T471_t() = default;
      ~T471_t() = default;

      int exec()
         {
            std::cout << "\n  cpuinfoGet()\n" << dashLine << std::endl;

            (void)cpuinfoGet(); // uses grep which uses compare

            std::cout << dashLine << std::endl;

            // count of lines which contain "processor" in linux file "/proc/cpuinfo"
            std::cout << "\n\n  " << coreCountGet()
                      << " cores on this system. (coreCountGet())\n\n" << std::endl;

            return(0);
         }


   private: // methods

      // returns std::string::npos when none of the patterns found,
      // else returns index of earliest found patterns of space delimited substr in
      size_t compare (const std::string& s,
                      std::string        patterns) // pass by value
         {
            size_t    found = std::string::npos;
            size_t patCount = 0;
            std::stringstream ssPat(patterns + ' '); // load patterns into ram based stringstream
            //                            ^^^^^ -- getline() can cause eof() in this
            const char delim = ' '; // see getline()

            do
            {
               if(0 == patterns.size()) break; // no patterns to search for, kick out
               if(0 == s.size())     break; // no string in which to search, kick out

               do {
                  std::string pat;
                  (void)std::getline(ssPat, pat, delim); // extract 1 space delimited pattern

                  if(false == ssPat.good())
                  {
                     if(ssPat.eof()) break; // quitely exit, a normal op

                     // let user know of patten problem
                     std::cerr << "\n  err pattern extract: " << patterns
                               << "  (" << patCount << ')' << std::endl;
                     break;
                  }
                  patCount += 1;

                  //trimLeadingWhiteSpace(patterns);  // tbr
                  //trimTrailingWhiteSpace(patterns); // tbr

                  if(0 == patterns.size()) break; // no more patterns

                  // search s for pat
                  found = s.find(pat);

                  if(found != std::string::npos) break; // one of the patterns found in s

               } while(1); // repeat until 1 found or all patterns tried

            }while(0);

            return(found);
         } // size_t compare (const std::string& s, std::string patterns)



      size_t grep(const std::string pfn,
                  const std::string patterns, // concatenated list of search patterns
                  std::ostream&     an_ostream = std::cout) // redirectable
         {
            size_t   foundCount = 0;

            an_ostream << "  grep (" << pfn << ", [" << patterns
                       << "] )" << std::endl;
            do
            {
               std::ifstream infile(pfn);

               if(!infile.is_open())
               {
                  an_ostream << pfn << " not found.\n" << std::endl; // tbr - std::cerr?
                  break; // skip over file op's (no close needed)
               }

               do
               {
                  if(infile.eof()) break;  // file empty?

                  std::string lineIn;
                  (void)getline(infile, lineIn); // default delimiter is \n

                  if (0 == lineIn.size()) continue; // empty line?

                  size_t found = compare(lineIn, patterns); // any of patterns in lineIn?

                  if(std::string::npos != found) // found at least one pattern
                  {
                     an_ostream << "  " << lineIn << std::endl; // found it, print it
                     foundCount += 1;
                  }
                  // else no pattern found - continue until eof of inFil

               } while(1);

               infile.close();

            }while(0);

            return(foundCount);
         } // size_t grep(const std::string pfn, const std::string patterns, std::ostream& an_ostream = std::cout)
      //                                space delimited list of ---^^^^^^^^



      size_t cpuinfoGet()
         {
            size_t count = grep("/proc/cpuinfo",  // pfn
                                "bogomips model name processor"); // patterns to search for
            std::cout << "\n  info lines: " << count << std::endl;
            return(count);
         } // size_t cpuinfoGet(void)



      size_t coreCountGet()
         {
            // create a no-ouptput output
            std::ofstream nullDev; // and do not open
            nullDev.setstate(std::ios_base::badbit); // set error, ignore errors, do not close

            size_t retVal = grep(std::string("/proc/cpuinfo"),
                                 std::string("processor"),  // line count of "processor" is core count
                                 nullDev); // nullDev -- no output
            return(retVal);
         } // size_t coreCountGet()(void)

   }; // class T471_t
} // namespace dtb


int main(int /*argc*/, char** /*argv[]*/)
{
  Time_t start_us = HRClk_t::now();

  int retVal = -1;
  {
     dtb::T471_t  t471;
     retVal = t471.exec();
  }

  auto  duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);

  std::cout << "  FINI   " << duration_us.count() << " us" << std::endl;
  return(retVal);
}

Output:

cpuinfoGet()
--------------------------------------------------------------
grep (/proc/cpuinfo, [bogomips model name processor] )
processor   : 0
model       : 75
model name  : AMD Athlon(tm) 64 X2 Dual Core Processor 5000+
bogomips    : 4809.67
processor   : 1
model       : 75
model name  : AMD Athlon(tm) 64 X2 Dual Core Processor 5000+
bogomips    : 4809.67

info lines: 8
--------------------------------------------------------------


 2 cores on this system. (coreCountGet())


 FINI   829 us

Sometimes, data can be a better solution than code.

std::map<std::string, int> values;
values["Seven"]=7;
values["seven"]=7;
values["7"]=7;
values["Six"]=6;
values["six"]=6;
values["6"]=6;

std::string input;
std::cin >> input;
std::cout << values[input];

As Vlad noted, you might be better of converting to lowercase first. This answer is just the straightforward conversion of your code to data. Note that this answer will use a default value of 0 for missing strings; your code left out such a default.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!