3379 Stimmen

Wie kann ich über die Wörter einer Zeichenkette iterieren?

Ich versuche, über die Wörter einer Zeichenkette zu iterieren.

Es kann davon ausgegangen werden, dass die Zeichenfolge aus durch Leerzeichen getrennten Wörtern besteht.

Beachten Sie, dass ich nicht in C-String-Funktionen oder diese Art von Zeichenmanipulation / Zugriff interessiert bin. Bitte geben Sie in Ihrer Antwort auch der Eleganz den Vorrang vor der Effizienz.

Die beste Lösung, die ich im Moment habe, ist:

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main()
{
    string s = "Somewhere down the road";
    istringstream iss(s);

    do
    {
        string subs;
        iss >> subs;
        cout << "Substring: " << subs << endl;
    } while (iss);
}

Gibt es eine elegantere Möglichkeit, dies zu tun?

693 Stimmen

Kumpel... Eleganz ist in meinen Augen nur eine schicke Umschreibung für "Effizienz, die hübsch aussieht". Scheuen Sie sich nicht, C-Funktionen und schnelle Methoden zu verwenden, um etwas zu erreichen, nur weil es nicht in einer Vorlage enthalten ist ;)

19 Stimmen

while (iss) { string subs; iss >> subs; cout << "Substring: " << sub << endl; }

0 Stimmen

@nlaq, Außer, dass Sie Ihr String-Objekt mit c_str() konvertieren müssten, und wieder zurück in einen String, wenn Sie es immer noch benötigen, um eine Zeichenfolge zu sein, nicht?

11voto

DannyK Punkte 1334

Ich habe meine eigenen mit strtok gerollt und verwendet Boost, um eine Zeichenfolge zu teilen. Die beste Methode, die ich gefunden habe, ist die C++ String Toolkit Bibliothek . Es ist unglaublich flexibel und schnell.

#include <iostream>
#include <vector>
#include <string>
#include <strtk.hpp>

const char *whitespace  = " \t\r\n\f";
const char *whitespace_and_punctuation  = " \t\r\n\f;,=";

int main()
{
    {   // normal parsing of a string into a vector of strings
        std::string s("Somewhere down the road");
        std::vector<std::string> result;
        if( strtk::parse( s, whitespace, result ) )
        {
            for(size_t i = 0; i < result.size(); ++i )
                std::cout << result[i] << std::endl;
        }
    }

    {  // parsing a string into a vector of floats with other separators
        // besides spaces

        std::string s("3.0, 3.14; 4.0");
        std::vector<float> values;
        if( strtk::parse( s, whitespace_and_punctuation, values ) )
        {
            for(size_t i = 0; i < values.size(); ++i )
                std::cout << values[i] << std::endl;
        }
    }

    {  // parsing a string into specific variables

        std::string s("angle = 45; radius = 9.9");
        std::string w1, w2;
        float v1, v2;
        if( strtk::parse( s, whitespace_and_punctuation, w1, v1, w2, v2) )
        {
            std::cout << "word " << w1 << ", value " << v1 << std::endl;
            std::cout << "word " << w2 << ", value " << v2 << std::endl;
        }
    }

    return 0;
}

Das Toolkit ist viel flexibler als dieses einfache Beispiel zeigt, aber sein Nutzen beim Parsen einer Zeichenkette in nützliche Elemente ist unglaublich.

11voto

Sam B Punkte 26515

Ich kann nicht glauben, wie übermäßig kompliziert die meisten dieser Antworten waren. Warum hat nicht jemand etwas so Einfaches vorgeschlagen?

#include <iostream>
#include <sstream>

std::string input = "This is a sentence to read";
std::istringstream ss(input);
std::string token;

while(std::getline(ss, token, ' ')) {
    std::cout << token << endl;
}

11voto

gibbz Punkte 11

Wie wäre es damit:

#include <string>
#include <vector>

using namespace std;

vector<string> split(string str, const char delim) {
    vector<string> v;
    string tmp;

    for(string::const_iterator i; i = str.begin(); i <= str.end(); ++i) {
        if(*i != delim && i != str.end()) {
            tmp += *i; 
        } else {
            v.push_back(tmp);
            tmp = ""; 
        }   
    }   

    return v;
}

0 Stimmen

Dies ist die beste Lösung, wenn Sie nur an einem einzigen Begrenzungszeichen trennen wollen. Die ursprüngliche Frage zielte jedoch auf Leerzeichen ab, d. h. auf eine beliebige Kombination aus einem oder mehreren aufeinanderfolgenden Leerzeichen oder Tabulatoren. Sie haben geantwortet stackoverflow.com/questions/53849

11voto

Andreas Spindler Punkte 6601

Kürzlich musste ich ein Wort in Unterwörter aufteilen, das in Großbuchstaben geschrieben war. Es gibt keine Begrenzungszeichen, nur Großbuchstaben.

#include <string>
#include <list>
#include <locale> // std::isupper

template<class String>
const std::list<String> split_camel_case_string(const String &s)
{
    std::list<String> R;
    String w;

    for (String::const_iterator i = s.begin(); i < s.end(); ++i) {  {
        if (std::isupper(*i)) {
            if (w.length()) {
                R.push_back(w);
                w.clear();
            }
        }
        w += *i;
    }

    if (w.length())
        R.push_back(w);
    return R;
}

So wird zum Beispiel "AQueryTrades" in "A", "Query" und "Trades" aufgeteilt. Die Funktion arbeitet mit schmalen und breiten Zeichenketten. Da sie das aktuelle Gebietsschema berücksichtigt, zerlegt sie "RaumfahrtÜberwachungsVerordnung" in "Raumfahrt", "Überwachung" und "Verordnung".

Hinweis std::upper sollte wirklich als Funktionsvorlagenargument übergeben werden. Dann kann die verallgemeinerte Version dieser Funktion an Begrenzungszeichen wie "," , ";" o " " también.

2 Stimmen

Es wurden 2 Revisionen durchgeführt. Das ist schön. Scheint, als hätte mein Englisch zu viel von einem "Deutsch". Wie auch immer, der Revisionist hat zwei kleinere Fehler nicht behoben, vielleicht weil sie sowieso offensichtlich waren: std::isupper als Argument übergeben werden kann, nicht std::upper . Zweitens setzen Sie eine typename vor dem String::const_iterator .

0 Stimmen

Std::isupper ist garantiert nur im <cctype>-Header (der C++-Version des C <ctype.h>-Headers) definiert, also müssen Sie diesen einschließen. Das ist so, als würde man sich darauf verlassen, dass man std::string verwenden kann, indem man den <iostream>-Header statt des <string>-Headers verwendet.

11voto

Hier ist eine andere Möglichkeit, es zu tun.

void split_string(string text,vector<string>& words)
{
  int i=0;
  char ch;
  string word;

  while(ch=text[i++])
  {
    if (isspace(ch))
    {
      if (!word.empty())
      {
        words.push_back(word);
      }
      word = "";
    }
    else
    {
      word += ch;
    }
  }
  if (!word.empty())
  {
    words.push_back(word);
  }
}

0 Stimmen

Ich glaube, dies könnte ein wenig optimiert werden, indem man word.clear() anstelle von word = "" . Durch den Aufruf der clear-Methode wird die Zeichenkette geleert, aber der bereits zugewiesene Puffer bleibt erhalten und wird bei weiteren Verkettungen wieder verwendet. Momentan wird für jedes Wort ein neuer Puffer angelegt, was zu zusätzlichen Zuweisungen führt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X