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?

29voto

J. Willus Punkte 476

C++20 segnet uns endlich mit einem split Funktion. Oder besser gesagt, einen Reichweitenadapter. Godbolt Link .

#include <iostream>
#include <ranges>
#include <string_view>

namespace ranges = std::ranges;
namespace views = std::views;

using str = std::string_view;

constexpr auto view =
    "Multiple words"
    | views::split(' ')
    | views::transform([](auto &&r) -> str {
        return {
            &*r.begin(),
            static_cast<str::size_type>(ranges::distance(r))
        };
    });

auto main() -> int {
    for (str &&sv : view) {
        std::cout << sv << '\n';
    }
}

4 Stimmen

Das sieht VIEL komplexer aus als die ursprünglich vorgeschlagene Lösung. Man sollte nicht so viel Arbeit machen müssen, nur um eine Zeichenkette zu teilen!

1 Stimmen

@UserX Dies mag zwar komplexer sein als die ursprünglich vorgeschlagene Lösung, ist aber auch effizienter.

0 Stimmen

Dies ist weitgehend dasselbe wie stackoverflow.com/a/54134243/6655648 .

26voto

zerm Punkte 2771

Wenn Sie boost verwenden möchten, aber eine ganze Zeichenkette als Begrenzungszeichen verwenden wollen (statt einzelner Zeichen wie in den meisten der zuvor vorgeschlagenen Lösungen), können Sie die boost_split_iterator .

Beispielcode mit praktischer Vorlage:

#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>

template<typename _OutputIterator>
inline void split(
    const std::string& str, 
    const std::string& delim, 
    _OutputIterator result)
{
    using namespace boost::algorithm;
    typedef split_iterator<std::string::const_iterator> It;

    for(It iter=make_split_iterator(str, first_finder(delim, is_equal()));
            iter!=It();
            ++iter)
    {
        *(result++) = boost::copy_range<std::string>(*iter);
    }
}

int main(int argc, char* argv[])
{
    using namespace std;

    vector<string> splitted;
    split("HelloFOOworldFOO!", "FOO", back_inserter(splitted));

    // or directly to console, for example
    split("HelloFOOworldFOO!", "FOO", ostream_iterator<string>(cout, "\n"));
    return 0;
}

23voto

Porsche9II Punkte 589

Verwendung von std::string_view und Eric Niebler's range-v3 Bibliothek:

https://wandbox.org/permlink/kW5lwRCL1pxjp2pW

#include <iostream>
#include <string>
#include <string_view>
#include "range/v3/view.hpp"
#include "range/v3/algorithm.hpp"

int main() {
    std::string s = "Somewhere down the range v3 library";
    ranges::for_each(s  
        |   ranges::view::split(' ')
        |   ranges::view::transform([](auto &&sub) {
                return std::string_view(&*sub.begin(), ranges::distance(sub));
            }),
        [](auto s) {std::cout << "Substring: " << s << "\n";}
    );
}

Durch die Verwendung einer Reihe for Schleife anstelle von ranges::for_each Algorithmus:

#include <iostream>
#include <string>
#include <string_view>
#include "range/v3/view.hpp"

int main()
{
    std::string str = "Somewhere down the range v3 library";
    for (auto s : str | ranges::view::split(' ')
                      | ranges::view::transform([](auto&& sub) { return std::string_view(&*sub.begin(), ranges::distance(sub)); }
                      ))
    {
        std::cout << "Substring: " << s << "\n";
    }
}

0 Stimmen

Yepp, das Angebot für die Basis sieht besser aus - da stimme ich zu

23voto

AJMansfield Punkte 3887

Hier ist eine Regex-Lösung, die nur die Standard-Regex-Bibliothek verwendet. (Ich bin ein wenig eingerostet, so kann es ein paar Syntaxfehler sein, aber dies ist zumindest die allgemeine Idee)

#include <regex.h>
#include <string.h>
#include <vector.h>

using namespace std;

vector<string> split(string s){
    regex r ("\\w+"); //regex matches whole words, (greedy, so no fragment words)
    regex_iterator<string::iterator> rit ( s.begin(), s.end(), r );
    regex_iterator<string::iterator> rend; //iterators to iterate thru words
    vector<string> result<regex_iterator>(rit, rend);
    return result;  //iterates through the matches to fill the vector
}

0 Stimmen

Ähnliche Antworten mit vielleicht besserem Regex-Ansatz: aquí y aquí .

22voto

Pratik Deoghare Punkte 32638

Es gibt eine Funktion namens strtok .

#include<string>
using namespace std;

vector<string> split(char* str,const char* delim)
{
    char* saveptr;
    char* token = strtok_r(str,delim,&saveptr);

    vector<string> result;

    while(token != NULL)
    {
        result.push_back(token);
        token = strtok_r(NULL,delim,&saveptr);
    }
    return result;
}

4 Stimmen

strtok stammt aus der C-Standardbibliothek, nicht aus C++. Es ist nicht sicher für die Verwendung in Multithreading-Programmen. Sie verändert die Eingabezeichenfolge.

14 Stimmen

Denn es speichert den char-Zeiger des ersten Aufrufs in einer statischen Variablen, so dass es sich bei den nachfolgenden Aufrufen, wenn NULL übergeben wird, merkt, welcher Zeiger verwendet werden soll. Wenn ein zweiter Thread aufruft strtok wenn ein anderer Thread noch in der Bearbeitung ist, wird dieser char-Zeiger überschrieben, und beide Threads haben dann falsche Ergebnisse. mkssoftware.com/docs/man3/strtok.3.asp

1 Stimmen

Wie bereits erwähnt, ist strtok unsicher und selbst in C wird strtok_r zur Verwendung empfohlen

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