Wie vergleiche ich mehrere Zeichenfolgen in einer if-Anweisung?

Lesezeit: 11 Minuten

Benutzer-Avatar
Jveto

Ich versuche, mehrere Möglichkeiten in einer if-Anweisung zu überprüfen.

Der Benutzer gibt eine Zeichenfolge ein, und dann überprüfe ich diese Zeichenfolge auf mehrere Möglichkeiten.

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

Also gibt es nur ein kurzes Beispiel dafür, was ich zu erreichen versuche. Irgendwelche Ideen?

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

    Benutzer2100815

    19. April 2017 um 1:29 Uhr

  • Was ist die Art von theString?

    – songyuanyao

    19. April 2017 um 1:31 Uhr

Benutzer-Avatar
Vlad aus Moskau

Ich nehme an, dass der Typ der Variablen theString ist std::string. Ansonsten zumindest dieser Vergleich

theString == "Seven"

macht keinen Sinn,

Die Bedingung in der if-Anweisung

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

ist äquivalent zu

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

und gibt immer nach true denn zumindest die Adresse des String-Literals "seven" ist nicht gleich null. Also dieser Unterausdruck ( "seven" ) sorgt dafür, dass der gesamte Ausdruck gleich true ist.

Du solltest schreiben

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

Aber es wäre besser, den String zunächst in Groß- oder Kleinschreibung umzuwandeln.

Zum Beispiel

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

Verwenden std::set und c ++ 11 können Sie einen Liner mit ähnlicher Syntax wie Ihrer erstellen.

Überprüfen Sie dies:

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

Benutzer-Avatar
Der QAGuy

Sie können eine Variable nicht wie in C++ mit mehreren Werten vergleichen. Sie sollten Folgendes tun:

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

Benutzer-Avatar
2785528

Dies ist ein klassisches Beispiel für die Identifizierung einer abgeleiteten Anforderung, die während der Implementierung gefunden wurde. Ich schlage vor, Sie erwägen, eine Funktion zu schreiben, um dies zu unterstützen.

Wechsel von

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

(was kein gültiges C++ ist, weil die if-Bedingung immer wahr ist)

ändern

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

und deklarieren und implementieren so etwas wie

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

Eigentlich bevorzuge ich folgendes. Das obige ist so etwas wie strstr(), wo dies mehr Funktionalität von std::string verwendet

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

Dies rufen Sie als auf

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

Die Implementierung muss durch Leerzeichen getrennte Muster auseinanderziehen, aber das ist nicht schwierig und kann leicht in einer Schleife implementiert werden, also gibt es keine Begrenzung, wie viele Vergleiche Sie testen möchten.


Wann sollten Sie erwägen, eine neue Funktion zur Unterstützung einer neuen abgeleiteten Anforderung zu erstellen?

Es ist meine Praxis, die neue Funktion zu erstellen, wenn ich 3 oder mehr Verwendungen identifizieren kann. Viel Glück.


Ich habe einen Code gefunden, den ich vor ein paar Jahren geschrieben habe, ihn repariert, Demos hinzugefügt …

Code kompiliert und scheint zu laufen, aber sehr wenig getestet.

  • Ich habe eine minimale Paketierung erstellt – einen Dummy-Namensraum (dtb – für die Werkzeugkiste von d___) und eine Dummy-Klasse (T471_t – Test 471).

dtb::T471_t bietet private Methoden für Ihre Überprüfung.

  • size_t Vergleich (const std::string s, std::string Muster)

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

    — verwendet vergleichen()

  • size_t cpuinfoGet()

    — verwendet grep

    — “wc < /proc/cpuinfo" (eine "bekannte Datei" auf Ubuntu) meldet 54 Zeilen auf meiner 2-Kern-Maschine, mehr Kerne, mehr Zeilen

  • size_t coreCountGet()

    — verwendet grep()

    — erstellt nullDev, um die normale grep-Ausgabe zu unterdrücken


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

Ausgabe:

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

Manchmal können Daten eine bessere Lösung sein als 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];

Wie Vlad angemerkt hat, ist es möglicherweise besser, zuerst in Kleinbuchstaben umzuwandeln. Diese Antwort ist nur die einfache Konvertierung Ihres Codes in Daten. Beachten Sie, dass diese Antwort einen Standardwert von 0 für fehlende Zeichenfolgen verwendet; Ihr Code hat einen solchen Standard ausgelassen.

  • Am Ende habe ich tatsächlich etwas über

    gelernt und es später in meinem Code angewendet. So wie ich es verstanden habe, habe ich alle meine Strings mit enum in “einfache” Datentypen konvertiert. Und dann habe ich eine switch-Anweisung verwendet, um alle diese Datentypen zu überprüfen, um zu bestimmen, welche Aktion zu ergreifen ist. Am Ende hatte ich über 40 Aufzählungswerte. Ich muss mir vielleicht genauer ansehen, was Sie gerade getan haben, wo mehrere Zeichenfolgen denselben Wert haben. Ich habe 1 C++-Klasse unter meinem Gürtel, also übersteigt das alles, was ich weiß, aber es ist großartig! Danke für die Hilfe!

    – Jveto

    19. April 2017 um 13:57 Uhr

  • @Jveto: Karten sind Container von Schlüssel-Wert-Paaren. Sie können (im Rahmen des Zumutbaren) einen beliebigen Schlüssel- und Werttyp auswählen, solange die Schlüssel sortiert werden können. Das Sortieren ist notwendig, damit die Containerelemente (die Paare) nach ihrem Schlüssel geordnet werden. Es macht es auch effizient, einen Wert zu finden, wenn nur der Schlüssel angegeben ist. Zeichenfolgen sind alphabetisch geordnet, damit sie in Karten verwendet werden können, und das habe ich hier verwendet. Der Wert, den ich jedem String-Schlüssel zuordne, ist der numerische Wert, also an int. Aber Sie können auch Enum-Werte oder Farben oder Zeiten oder …

    – MSalter

    19. April 2017 um 14:10 Uhr

  • Am Ende habe ich tatsächlich etwas über

    gelernt und es später in meinem Code angewendet. So wie ich es verstanden habe, habe ich alle meine Strings mit enum in “einfache” Datentypen konvertiert. Und dann habe ich eine switch-Anweisung verwendet, um alle diese Datentypen zu überprüfen, um zu bestimmen, welche Aktion zu ergreifen ist. Am Ende hatte ich über 40 Aufzählungswerte. Ich muss mir vielleicht genauer ansehen, was Sie gerade getan haben, wo mehrere Zeichenfolgen denselben Wert haben. Ich habe 1 C++-Klasse unter meinem Gürtel, also übersteigt das alles, was ich weiß, aber es ist großartig! Danke für die Hilfe!

    – Jveto

    19. April 2017 um 13:57 Uhr

  • @Jveto: Karten sind Container von Schlüssel-Wert-Paaren. Sie können (im Rahmen des Zumutbaren) einen beliebigen Schlüssel- und Werttyp auswählen, solange die Schlüssel sortiert werden können. Das Sortieren ist notwendig, damit die Containerelemente (die Paare) nach ihrem Schlüssel geordnet werden. Es macht es auch effizient, einen Wert zu finden, wenn nur der Schlüssel angegeben ist. Zeichenfolgen sind alphabetisch geordnet, damit sie in Karten verwendet werden können, und das habe ich hier verwendet. Der Wert, den ich jedem String-Schlüssel zuordne, ist der numerische Wert, also an int. Aber Sie können auch Enum-Werte oder Farben oder Zeiten oder …

    – MSalter

    19. April 2017 um 14:10 Uhr

1013100cookie-checkWie vergleiche ich mehrere Zeichenfolgen in einer if-Anweisung?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy