【问题标题】:How to compare multiple strings inside an if statement?如何比较 if 语句中的多个字符串?
【发布时间】:2017-04-19 01:28:07
【问题描述】:

我正在尝试检查 if 语句中的多种可能性。

用户输入一个字符串,然后我根据多种可能性检查该字符串。

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

所以这里只是一个我想要完成的简单示例。有什么想法吗?

【问题讨论】:

  • if (theString == "Seven" || theString == "seven" || theString == "7")
  • theString的类型是什么?

标签: c++ string conditional-statements


【解决方案1】:

使用 std::set 和 c++11,您可以使用与您的语法相似的一行代码。

检查一下:

#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";
  }
}

【讨论】:

    【解决方案2】:

    我假设变量theString 的类型是std::string。否则至少这个比较

    theString == "Seven"
    

    没有意义,

    if 语句中的条件

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

    等价于

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

    并且总是产生true,因为至少字符串文字"seven"的地址不等于0。所以这个子表达式( "seven" ) 规定整个表达式都等于真。

    你应该写

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

    但最好先将字符串转换为大写或小写。

    例如

    #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;
    }
    

    【讨论】:

      【解决方案3】:

      您不能像在 C++ 中那样将一个变量与多个值进行比较。你应该这样做:

      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;
       }
      

      【讨论】:

        【解决方案4】:

        这是识别在实施过程中发现的派生需求的经典示例。我建议你考虑写一个函数来支持它。

        改变

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

        (这不是有效的 c++,因为 if 条件始终为真)

        改成

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

        并声明和实现类似的东西

        // 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
        }
        

        我实际上更喜欢以下内容。上面有点像 strstr(),它使用了 std::string 的更多功能

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

        你调用这个

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

        实现必须梳理空格分隔的模式..但这并不难,并且可以很容易地在循环中实现,因此您希望测试的比较次数没有限制。


        什么时候应该考虑创建一个新函数来支持新的派生需求?

        当我能确定 3 种或更多用途时,我会创建新功能。 祝你好运。


        找到了我几年前写的一些代码,修复了它,添加了演示......

        代码可以编译并且似乎可以运行,但测试很少。

        • 我创建了最小的包装——一个虚拟命名空间(dtb - 用于 d___ 的工具箱)和一个虚拟类(T471_t - 测试 471)

        dtb::T471_t 提供私有方法供您查看。

        • size_t 比较(const std::string s, std::string patterns)

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

          -- 使用 compare()

        • size_t cpuinfoGet()

          -- 使用 grep

          -- “wc /cpuinfo”(ubuntu 上的一个“众所周知的文件”)在我的 2 核机器上报告 54 行,更多内核,更多行

        • size_t coreCountGet()

          -- 使用 grep()

          -- 创建nullDev来抑制grep正常输出


        #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);
        }
        

        输出:

        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
        

        【讨论】:

        • "not valid c++" - 实际上它是有效的 C++。这很不幸,但需要与 C 向后兼容。至于您建议的替代方案,我认为这是完全糟糕的设计。从使用int作为布尔类型到任意限制参数的类型和数量,它只是忽略了C++对C的改进。使用空格作为字符串的运行时分隔符真的很糟糕,如果你的输入包含一个空格怎么办自己?
        • @MSalters - 感谢您的反馈。我想你的意思是它会编译,但总是返回 true。我认为这确实使它无效,此外,这是一个典型的错误。出于显而易见的原因,我们大多数人都认识到这一点。我承认我不记得曾经在生产代码中使用过这种“糟糕”的设计。我只是猜测这是他现在想要做的。更多的练习可能会改变他的想法。我的想象力经常让我失望。 int 返回码来自 C++ 的 std::string::compare 方法。
        【解决方案5】:

        有时,数据可能是比代码更好的解决方案。

        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];
        

        正如 Vlad 所说,您最好先转换为小写字母。这个答案只是将您的代码直接转换为数据。请注意,此答案将使用默认值 0 来表示缺少的字符串;您的代码省略了这样的默认值。

        【讨论】:

        • 我实际上最终了解了 并将其应用到我的代码中。我理解它的方式是 - 我使用枚举将所有字符串转换为“简单”数据类型?然后我使用 switch 语句检查所有这些数据类型以确定要采取的操作。我最终得到了 40 多个枚举值。我可能需要更多地研究您刚刚所做的事情,其中​​多个字符串等于相同的值。我有 1 类 C++,所以这超出了我所知道的范围,但它很棒!感谢您的帮助!
        • @Jveto:地图是键值对的容器。您可以(在合理范围内)选择任何键和值类型,只要键可以排序。排序是必要的,因此容器元素(对)按其键排序。它还可以有效地找到仅给定键的值。字符串按字母顺序排列,因此可以在地图中使用,我在这里使用过。我与每个字符串键关联的值是数值,所以是int。但您也可以使用枚举值、颜色、时间或 ...
        猜你喜欢
        • 1970-01-01
        • 2016-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-15
        • 1970-01-01
        相关资源
        最近更新 更多