Analysieren eines durch Kommas getrennten std::string [duplicate]

Lesezeit: 6 Minuten

Wenn ich einen std::string habe, der eine durch Kommas getrennte Liste von Zahlen enthält, wie kann ich die Zahlen am einfachsten analysieren und in ein Integer-Array einfügen?

Ich möchte dies nicht verallgemeinern, um etwas anderes zu analysieren. Nur eine einfache Zeichenfolge aus durch Kommas getrennten Ganzzahlen wie “1,1,1,1,2,1,1,1,0”.

  • für alle, die suchen, wie man durch Kommas getrennte Zeichenfolgen analysiert stackoverflow.com/questions/11719538/…

    – Sam B

    4. September 2021 um 15:49 Uhr

Geben Sie jeweils eine Zahl ein und prüfen Sie, ob das folgende Zeichen ist ,. Wenn ja, verwerfen Sie es.

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

int main()
{
    std::string str = "1,2,3,4,5,6";
    std::vector<int> vect;

    std::stringstream ss(str);

    for (int i; ss >> i;) {
        vect.push_back(i);    
        if (ss.peek() == ',')
            ss.ignore();
    }

    for (std::size_t i = 0; i < vect.size(); i++)
        std::cout << vect[i] << std::endl;
}

  • Ich denke, dies wird fehlschlagen, wenn vor dem ein Leerzeichen vorhanden ist.

    – KeithB

    12. Dezember 2009 um 23:09 Uhr

  • Ja, das wird es, aber Leerzeichen waren nicht Teil des ursprünglichen Problems

    – Benutzer229321

    12. Dezember 2009 um 23:12 Uhr

  • Um das abzudecken: if (ss.peek() == ',' || ss.peek() == ' ')

    – safe_malloc

    31. Oktober 2014 um 9:27 Uhr


  • Wie kann man es ändern, wenn man die Werte in ein Array bekommen soll? (Wenn die Anzahl der Elemente bereits bekannt ist)

    – S.Dan

    10. November 2014 um 12:22 Uhr


  • @safe_malloc: Sollte das nicht sein while (ss.peek() == ',' || ss.peek() == ' ')

    – Saurabhöhen

    10. Mai 2016 um 16:30 Uhr


Etwas weniger ausführlich, std und nimmt alles, was durch ein Komma getrennt ist.

stringstream ss( "1,1,1,1, or something else ,1,1,1,0" );
vector<string> result;

while( ss.good() )
{
    string substr;
    getline( ss, substr, ',' );
    result.push_back( substr );
}

  • Das hat bei mir super funktioniert. sehr wenige Codezeilen und es funktioniert großartig.

    – MauricioSanchez

    3. Dezember 2014 um 20:36 Uhr

  • Leicht zu lesen und handhabt Leerzeichen gut. Danke!

    – sudo make install

    22. September 2015 um 11:02 Uhr

  • Einfach, leicht zu lesen, erfordert keine spezielle Bibliothek!

    – Johan Engblom

    5. November 2015 um 13:58 Uhr

  • Beachten Sie, dass dies für eine leere Zeichenfolge immer noch ausreicht result.push_back(""); das ist wahrscheinlich nicht das, was Sie wollen.

    – Timmm

    29. August 2017 um 10:58 Uhr

  • Betrachtet es das Leerzeichen nach dem Komma als Teil der Zeichenfolge? dh das Leerzeichen vor oder in “oder etwas anderes”?

    – Rajesh

    6. März 2020 um 6:43 Uhr

Ein weiterer, etwas anderer Ansatz: Verwenden Sie ein spezielles Gebietsschema, das Kommas als Leerzeichen behandelt:

#include <locale>
#include <vector>

struct csv_reader: std::ctype<char> {
    csv_reader(): std::ctype<char>(get_table()) {}
    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());

        rc[','] = std::ctype_base::space;
        rc['\n'] = std::ctype_base::space;
        rc[' '] = std::ctype_base::space;
        return &rc[0];
    }
}; 

Um dies zu nutzen, müssen Sie imbue() ein Stream mit einem Gebietsschema, das diese Facette enthält. Sobald Sie das getan haben, können Sie Zahlen lesen, als wären die Kommas überhaupt nicht vorhanden. Nur zum Beispiel lesen wir durch Kommas getrennte Zahlen aus der Eingabe und schreiben dann eine pro Zeile auf die Standardausgabe:

#include <algorithm>
#include <iterator>
#include <iostream>

int main() {
    std::cin.imbue(std::locale(std::locale(), new csv_reader()));
    std::copy(std::istream_iterator<int>(std::cin), 
              std::istream_iterator<int>(),
              std::ostream_iterator<int>(std::cout, "\n"));
    return 0;
}

  • Die kreativste Antwort, die ich je gesehen habe!

    – Joko

    16. Mai 2011 um 16:37 Uhr

  • +1 verwendet nur std und es ist eine saubere und einfache Lösung. Kein Spähen und Ignorieren von Zeichen!

    – kravemir

    23. Februar 2013 um 14:30 Uhr


  • Hier ist ein funktionierendes Beispiel, falls jemand es ausprobieren wollte: ideone.com/RX5o10

    – kravemir

    23. Februar 2013 um 14:40 Uhr

  • Beachten Sie, dass das obige Beispiel explodiert, wenn die Eingabe wie “1, 2, 3, 4, 5 …” aussieht. Sie müssen die Zeile rc hinzufügen[‘ ‘] = ctype_base::space;. Ich brauchte eine Weile, um es herauszufinden

    – eine Kurie

    27. März 2013 um 19:35 Uhr

  • Ich fürchte, diese Lösung unterstützt jedoch keine leeren Zeichenfolgen, sie werden einfach übersprungen. Nehmen Sie zum Beispiel diese Eingabe: 1,2,3,,5,6,7.

    – Fabio A.

    24. September 2015 um 8:20 Uhr

Die C++-String-Toolkit-Bibliothek (Strtk) hat folgende Lösung für dein Problem:

#include <string>
#include <deque>
#include <vector>
#include "strtk.hpp"
int main()
{ 
   std::string int_string = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15";
   std::vector<int> int_list;
   strtk::parse(int_string,",",int_list);

   std::string double_string = "123.456|789.012|345.678|901.234|567.890";
   std::deque<double> double_list;
   strtk::parse(double_string,"|",double_list);

   return 0;
}

Weitere Beispiele sind zu finden Hier

Alternative Lösung mit generischen Algorithmen und Boost.Tokenizer:

struct ToInt
{
    int operator()(string const &str) { return atoi(str.c_str()); }
};

string values = "1,2,3,4,5,9,8,7,6";

vector<int> ints;
tokenizer<> tok(values);

transform(tok.begin(), tok.end(), back_inserter(ints), ToInt());

  • wenn Sie Boost.Tokenizer verwenden, warum nicht ersetzen atoi durch boost::lexical_cast?

    – Andriy Tylychko

    9. Februar 2011 um 23:51 Uhr

Viele ziemlich schreckliche Antworten hier, also füge ich meine hinzu (einschließlich Testprogramm):

#include <string>
#include <iostream>
#include <cstddef>

template<typename StringFunction>
void splitString(const std::string &str, char delimiter, StringFunction f) {
  std::size_t from = 0;
  for (std::size_t i = 0; i < str.size(); ++i) {
    if (str[i] == delimiter) {
      f(str, from, i);
      from = i + 1;
    }
  }
  if (from <= str.size())
    f(str, from, str.size());
}


int main(int argc, char* argv[]) {
    if (argc != 2)
        return 1;

    splitString(argv[1], ',', [](const std::string &s, std::size_t from, std::size_t to) {
        std::cout << "`" << s.substr(from, to - from) << "`\n";
    });

    return 0;
}

Schöne Eigenschaften:

  • Keine Abhängigkeiten (z. B. Boost)
  • Kein verrückter Einzeiler
  • Leicht verständlich (hoffe ich)
  • Behandelt Leerzeichen vollkommen in Ordnung
  • Weist keine Splits zu, wenn Sie dies nicht möchten, z. B. können Sie sie wie gezeigt mit einem Lambda verarbeiten.
  • Fügt Zeichen nicht einzeln hinzu – sollte schnell sein.
  • Wenn Sie C ++ 17 verwenden, können Sie es ändern, um a zu verwenden std::stringview und dann werden keine Zuweisungen vorgenommen und es sollte extrem schnell sein.

Einige Designoptionen, die Sie möglicherweise ändern möchten:

  • Leere Einträge werden nicht ignoriert.
  • Ein leerer String ruft f() einmal auf.

Beispiel Ein- und Ausgänge:

""      ->   {""}
","     ->   {"", ""}
"1,"    ->   {"1", ""}
"1"     ->   {"1"}
" "     ->   {" "}
"1, 2," ->   {"1", " 2", ""}
" ,, "  ->   {" ", "", " "}

  • wenn Sie Boost.Tokenizer verwenden, warum nicht ersetzen atoi durch boost::lexical_cast?

    – Andriy Tylychko

    9. Februar 2011 um 23:51 Uhr

Sie können auch die folgende Funktion verwenden.

void tokenize(const string& str, vector<string>& tokens, const string& delimiters = ",")
{
  // Skip delimiters at beginning.
  string::size_type lastPos = str.find_first_not_of(delimiters, 0);

  // Find first non-delimiter.
  string::size_type pos = str.find_first_of(delimiters, lastPos);

  while (string::npos != pos || string::npos != lastPos) {
    // Found a token, add it to the vector.
    tokens.push_back(str.substr(lastPos, pos - lastPos));

    // Skip delimiters.
    lastPos = str.find_first_not_of(delimiters, pos);

    // Find next non-delimiter.
    pos = str.find_first_of(delimiters, lastPos);
  }
}

994460cookie-checkAnalysieren eines durch Kommas getrennten std::string [duplicate]

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

Privacy policy