Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Äquivalent zu explode() in C++?

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
20.06.2009, 23:43 Uhr
Yadgar



High!

Ich will aus einer in ein vector-"Array" eingelesenen ASCII-Textdatei, die durch Kommata getrennte Zahlen enthält, zeilenweise diese Zahlenwerte extrahieren und frage mich, ob es für vector-Objekte eine Funktion gibt, die explode() in PHP entspricht - eine Funktion, der man den Namen des zu zerlegenden Arrays und das gültige Trennzeichen übergibt und die ein Array von Zeichenketten (in diesem Fall ein Array von vector-Objekten) zurückgibt. Existiert eine solche Funktion oder muss ich mich doch in die Niederungen der char-Arrays begeben, dynamische Speicherverwaltung inbegriffen?

Lassen sich vector-Objekte eventuell in strings (nicht C-Strings, sondern aus string.h) umwandeln?

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
21.06.2009, 02:14 Uhr
0xdeadbeef
Gott
(Operator)


<string.h> ist ein C-Header, der C-String-Funktionen enthält. std::string befindet sich in <string>.

Wie dem aber auch sei, eine Funktion direkt gibt es nicht, aber die ist einfach zusammengeschustert:

C++:
#include <sstream>
#include <string>
#include <vector>

std::vector<std::string> explode(std::string const &line, char delim) {
  std::istringstream in(line);
  std::vector<std::string> result;
  std::string token;

  while(std::getline(in, token, delim)) {
    result.push_back(token);
  }

  return result;
}

// ...

std::vector<std::string> tokens = explode("foo,bar,baz", ',');


Allerdings finge ich das wohl schon mit einem Parser an. Ich benutze für sowas in der Regel boost.spirit, das sieht dann etwa so aus:

C++:
#include <boost/spirit/include/qi.hpp>

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

bool explode(std::string const &src,
             std::vector<int> &dest,
             char delim = ',') {
  namespace bs = boost::spirit;

  std::string::const_iterator first = src.begin(),
                              last  = src.end  ();

  bool r = bs::qi::phrase_parse(first,
                                last,
                                bs::int_ % delim,
                                dest,
                                bs::ascii::space);

  return r && first == last;
}

int main() {
  std::vector<int> v;

  if(explode("1,2,3,4,5", v)) {
    std::copy(v.begin(),
              v.end(),
              std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
  } else {
    std::cout << "Fehler!" << std::endl;
  }
}


Dabei ist bs::int_ % delim die spiritisierte EBNF für von delim getrennte Ganzzahlen. Der resultierende Parser ist praktischerweise schon auf std::vector<int> attributisiert, was uns einen Haufen Arbeit erspart.

Die dahinterliegenden Konzepte sind hier: www.boost.org/doc/libs/1_39_0/libs/spirit/doc/html/spirit/qi_and_karma.html erklärt, wobei die Dokumentation für spirit2 sich leider noch im Aufbaustadium befindet.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 21.06.2009 um 02:20 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
21.06.2009, 11:08 Uhr
Yadgar



High!


Zitat von 0xdeadbeef:
<string.h> ist ein C-Header, der C-String-Funktionen enthält. std::string befindet sich in <string>.

Wie dem aber auch sei, eine Funktion direkt gibt es nicht, aber die ist einfach zusammengeschustert:

C++:
#include <sstream>
#include <string>
#include <vector>

std::vector<std::string> explode(std::string const &line, char delim) {
  std::istringstream in(line);
  std::vector<std::string> result;
  std::string token;

  while(std::getline(in, token, delim)) {
    result.push_back(token);
  }

  return result;
}

// ...

std::vector<std::string> tokens = explode("foo,bar,baz", ',');





Sieht schon mal vielversprechend aus... aber am Ende müsste ich dann doch wieder auf C-Strings zurückgreifen, nämlich wenn ich die einzelnen Strings im Rückgabe-Vektor in Zahlen umwandele... oder gibt es so etwas wie atof/atoi auch für string.h-Strings?

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
21.06.2009, 12:22 Uhr
0xdeadbeef
Gott
(Operator)


Üblicherweise macht man sowas in C++ etwa so:

C++:
#include <sstream>
#include <stdexcept>

template <typename to, typename from>
to convert(from const &src) {
  std::stringstream converter;
  to dest;

  converter << src;
  converter >> dest;

  if(!converter) {
    throw std::invalid_argument("Konvertierung fehlgeschlagen");
  }

  return dest;
}


...um es dann später so zu benutzen:

C++:
#include <cstddef>
#include <iostream>

int main() {
  char const *const data[] = { "123", "234", "foobar", "345" };

  for(std::size_t i = 0; i < 4; ++i) {
    try {
      std::cout << convert<int>(data[i]) << std::endl;
    } catch(std::exception &e) {
      std::cerr << "Fehler beim Verarbeiten vom \"" << data[i] << "\": "
                << e.what() << std::endl;
    }
  }
}


Prinzipiell kann man auch atoi(foo.c_str()) benutzen, aber atoi ist auf int beschränkt (also in Vorlagen unbrauchbar) und hat keinerlei Fehlerbehandlung.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 21.06.2009 um 12:22 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
21.06.2009, 19:11 Uhr
Yadgar



High!


Zitat von 0xdeadbeef:
<string.h> ist ein C-Header, der C-String-Funktionen enthält. std::string befindet sich in <string>.

Wie dem aber auch sei, eine Funktion direkt gibt es nicht, aber die ist einfach zusammengeschustert:

C++:
#include <sstream>
#include <string>
#include <vector>

std::vector<std::string> explode(std::string const &line, char delim) {
  std::istringstream in(line);
  std::vector<std::string> result;
  std::string token;

  while(std::getline(in, token, delim)) {
    result.push_back(token);
  }

  return result;
}

// ...

std::vector<std::string> tokens = explode("foo,bar,baz", ',');





Wenn ich deine Funktion "explode" verwende, wird das Programm zwar kompiliert, ich bekomme aber folgende Laufzeit-Fehlermeldung

terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc

Was läuft da falsch?

Hier der Kontext:


C++:
  while (j < buffer.size())
  {
    line.append(1, buffer.at(j));
    if (buffer.at(j+1)=='\n')
    {
      i++;
      numbers = explode(line, ',');
      // cout << numbers.size() << endl;
      /* for (short a=0; a<numbers.size(); a++)
        cout << numbers.at(a) << endl; */

      line = "";
/*      switch (buffer.at(j))
      {
        case '0':
          type = "metres straight";
          
        break;
        case '1':
        break;
      }    */

      anim << "      #range(" << start_s << ", " << end_s << ") // track segment #" << i << endl;
      anim << "
      #break" << endl;
    }
    j++;
}



Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
21.06.2009, 19:21 Uhr
0xdeadbeef
Gott
(Operator)


std::bad_alloc heißt normalerweise, dass ihm der Speicher ausgegangen ist. Kuck mal mit nem Debugger, von wo der die Exception eigentlich schmeißt, und gib mir mal einen möglichst kleinen Testcase, der das Verhalten reproduziert - mit dem Teilprogramm da oben kann ich nicht viel anfangen, weil ich von der Hälfte der Variablen nicht mal den Typ kenne.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
21.06.2009, 19:33 Uhr
Yadgar



High!


Zitat von 0xdeadbeef:
std::bad_alloc heißt normalerweise, dass ihm der Speicher ausgegangen ist. Kuck mal mit nem Debugger, von wo der die Exception eigentlich schmeißt, und gib mir mal einen möglichst kleinen Testcase, der das Verhalten reproduziert - mit dem Teilprogramm da oben kann ich nicht viel anfangen, weil ich von der Hälfte der Variablen nicht mal den Typ kenne.


Gerne:


C++:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

vector<string> explode (string const &line, char delim)
{
  istringstream in(line);
  vector<string> result;
  string token;

  while(getline(in, token, delim))
  {
    result.push_back(token);
  }
}

int main(void)
{
  string test("23,89,10");
  vector<string> container;
  
  container = explode(test, ',');
  
  cout << container.at(0) << endl;
  cout << container.at(1) << endl;
  cout << container.at(2) << endl;
  
  return 0;
}



Wieder der gleiche Fehler:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc

Wie debugge ich von der Konsole aus?

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
21.06.2009, 19:56 Uhr
0xdeadbeef
Gott
(Operator)


Naja, wenn du das

C++:
  return result;


in der explode-Funktion vergisst, ist das ja auch kein Wunder.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
21.06.2009, 20:00 Uhr
Yadgar




Zitat von 0xdeadbeef:
Naja, wenn du das

C++:
  return result;


in der explode-Funktion vergisst, ist das ja auch kein Wunder.


<anKopfklatsch>
Boinks!
</anKopfklatsch>

Und mir kam die Funktion schon so komisch vor...

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
21.06.2009, 20:12 Uhr
Yadgar



High!


Zitat von 0xdeadbeef:
Naja, wenn du das

C++:
  return result;


in der explode-Funktion vergisst, ist das ja auch kein Wunder.


Mein kleines Testprogramm funktioniert jetzt einwandfrei... aber mein ursprüngliches Projekt schmeißt jetzt einen anderen Laufzeitfehler:

terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check

Hier die verwendeten Datentypen

vector<char> buffer; // hier hinein wird das ASCII-Textfile von der Festplatte eingelesen
unsigned long j = 0; // zählt die char-Elemente in buffer
unsigned short i = 0; // zählt die Zeilenumbrüche in buffer, spielt hier allerdings noch keine Rolle
string line(""); // nimmt jeweils eine "Zeile" aus buffer auf, die dann mit explode in Zahlen-Strings zerlegt wird
vector<string> numbers; // nimmt den von explode zurückgegebenen Vektor vom Typ string auf

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: