So zerlegt man einen String...



  • Hallo,

    Da ich bereits in anderen Foren die Frage gelesen habe, wie man einen String in "Einzelteile" zerlegen kann, habe ich dazu eine Funktion geschrieben.

    Es geht darum, Einzelwörter aus einem Gesamtstring zu excludieren. Dazu ist es aber notwendig, die einzelnen Wörter mit einem Trennzeichen zu versehen, damit der Extrahierer auch weis, wo ein Wort beginnt und wo es endet.

    Der folgende Code ist bereits als eine Header programmiert. Somit müsst ihr den Code nur noch als Header abspeichern, und könnt sie dann benutzen. Hier erstmal der Code, und danach ein Anwendungsbeispiel:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class exclude
    {
      public: string excluder(string &source,char poi,int pos);
    };
    
    string exclude::excluder(string &source,char poi,int pos)
    {
      int ex_beg; //Position des ersten gefundenen "poi"
      int ex_end; //Position des "poi", der als nächstes gefunden wurde
      int c; 
      int i;
    
      for(i=0;i<source.length();i++)
      {
       if(source[i] == poi)
        {
        pos--;
        if(pos<0){ ex_beg = i+1;break;}
        }  
      }
      for(i = ex_beg +1;i<source.length();i++)
      {
       if(source[i] == poi)
       {
       ex_end =i-1; break;
       }
      }
      return source.substr(ex_beg, ex_end-ex_beg+1);  
    }
    

    Erstmal die Syntax der Funktion: excluder(Quellstring,'Trennzeichen',Position);
    Nachdem ihr den Code in eine Header gepackt habt, könnt ihr sie folgendermaßen anwenden:

    #include <iostream>
    #include "exclude.h"   //Der Name bleibt euch überlassen.
    using namespace std;
    
    exclude excluding;     //Objekt erstellen.
    int main ()
    {
    string textbeispiel = ";Das;ist;ein;Beispiel;"; //Zu extrahierender string.
    string zerlegt [4]; //In diesem String werden die einzelnen Wörter abgelegt.
    
    zerlegt[0] = excluding.excluder(textbeispiel,';',0); 
    zerlegt[1] = excluding.excluder(textbeispiel,';',1); 
    zerlegt[2] = excluding.excluder(textbeispiel,';',2); 
    zerlegt[3] = excluding.excluder(textbeispiel,';',3); 
    
    cout<<zerlegt[0]<<endl; //Ausgabe: "Das"
    cout<<zerlegt[1]<<endl; //Ausgabe: "ist"
                            //.... usw.
    }
    

    Ihr könnt das ganze natürlich in eine Schleife packen. Da könnt ihr sehr kreativ sein. Ich weis, es ist umständlich, dass ich das Ergebnis des excluders erstmal dem string "zerlegt" zuweise, ich hätte auch gleich schreiben können: cout<<excluding.excluder(textbeispiel,';',3)<<endl; , aber das funktionierte bei mir aus irgendeinem Grund nicht.

    Ich hoffe, diese Funktion bringt euch in Zukunft etwas!
    Bei Fragen einfach posten.
    MFG mikey.



  • Sorry, aber meiner Meinung nach ist dein Code sehr Praxisfremd.
    Wer;schreibt;seine;Texte;mit;Semicolon;getrennt???
    Wenn du statt der Abfrage auf (ASCII 32 == Space) vergleichst wäre es besser.

    LG Sascha



  • Also als Vorbild, wie man so etwas macht, solltet Ihr euch das nicht nehmen. Da gibt es einiges zu bemängeln.

    [] Wenn das ein Header ist, gehört kein "using namespace std" rein (meiner Meinung nach gehört das nirgends rein, aber das ist ein anderes Thema)
    [
    ] Das ist eine Funktion und was eine Funktion ist, soll auch so geschrieben sein. Warum diese Klasse?
    [] Einen String als "string&" zu übergeben und ihn nicht zu verändern ist schlichtweg falsch. Entweder als Kopie "std::string source" oder als "const std::string& source".
    [
    ] Der Name "excluder" sagt mir, daß etwas exkludiert wird. Du sagst aber richtigerweise, daß der String in Einzelteile zerlegt wird. Also eher "splitter" oder so.
    [] Zum finden eines Zeichens in einem String oder auch eines anderen Containers dient der find-algorithmus. Oder aber die find-Methoden aus std::string
    [
    ] Statt std::string könntest Du daraus ein Template machen, so das man auch andere std::basic_string-Klassen verwenden kann.
    [] Die "pos" Variable wäre ein Kandidat für ein Datenmember der Klasse. Es ist eine Zustandsvariable Deiner Iteration. Damit würde die Klasse dann wieder Sinn machen.
    [
    ] Du solltest Dir mal boost anschauen (http://www.boost.org/). Da insbesondere den Tokenizer.
    [*] Korrigier mal die Einrückung

    Tntnet



  • [*] Das ist eine Funktion und was eine Funktion ist, soll auch so geschrieben sein. Warum diese Klasse?

    durch eine klasse wird seine funktion objektorientierter denke ich mal.



  • kebit schrieb:

    [*] Das ist eine Funktion und was eine Funktion ist, soll auch so geschrieben sein. Warum diese Klasse?

    durch eine klasse wird seine funktion objektorientierter denke ich mal.

    Objektorientierter? Das Wort muss ich mir unbedingt merken! 😉

    @Poster:
    Da gibts noch viele Dinge die zu optimieren wären (auch Kleinigkeiten) bevor du sowas auf deine Mitmenschen loslässt! 🙂



  • mikey schrieb:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class exclude
    {
      public: string excluder(string &source,char poi,int pos);
    };
    
    string exclude::excluder(string &source,char poi,int pos)
    {
      int ex_beg; //Position des ersten gefundenen "poi"
      int ex_end; //Position des "poi", der als nächstes gefunden wurde
      int c; 
      int i;
      
      for(i=0;i<source.length();i++)
      {
       if(source[i] == poi)
        {
        pos--;
        if(pos<0){ ex_beg = i+1;break;}
        }  
      }
      for(i = ex_beg +1;i<source.length();i++)
      {
       if(source[i] == poi)
       {
       ex_end =i-1; break;
       }
      }
      return source.substr(ex_beg, ex_end-ex_beg+1);  
    }
    

    Wenn ich jetzt damit CSV Dateien einlese, was passiert bei einem "Hans-Peter;Müller;;Bäckerweg 13", also wenn eine Spalte mal frei ist?
    Und, was passiert wenn das Trennzeichen garnicht in der Zeichenkette enthalten ist?



  • Och wenn wir schon dabei sind Quellcode auf mitmenschen los zu lassen, hätte ich zu dem Thema auch noch was in der alten Quellcodekiste gefunden , was man zerreisen kann 😃

    // Splittet anhand verschiedener Zeichen. z.B. |<> würde | und < und > als Trennzeichen nehmen bei
    // a|b<c>d
    
    std::list<std::string> KB::splitting(std::string tosplitt,const std::string & trennzeichen,bool mayempty /*= false*/)
    {
    
        std::string::size_type pos;
        std::list<std::string> temp;
    
        while((pos = tosplitt.find_first_of(trennzeichen)) != std::string::npos)
        {
            std::string toadd(tosplitt.substr(0,pos));
            trim(toadd);
            if(!toadd.empty() || mayempty)
    			temp.push_back(toadd);
    
            tosplitt.erase(0,pos+trennzeichen.length());
        }
        if(!tosplitt.empty())
            temp.push_back(tosplitt);
    
        return temp;
    }
    




  • kebit schrieb:

    [*] Das ist eine Funktion und was eine Funktion ist, soll auch so geschrieben sein. Warum diese Klasse?

    durch eine klasse wird seine funktion objektorientierter denke ich mal.

    Man sollte alles beim Namen nennen. Ich liebe C++, weil es Ausdrucksmittel für so vieles bietet. Wenn eine Funktionalität keinen Zustand hat, dann braucht es kein Objekt. Es wird nicht "objektorientierter" nur weil Du ein künstliches Objekt ohne Sinn erzeugst.



  • Hallo,
    danke erstmal dür die Kommentare. Allerdings gibt es da noch einiges zu besprechen:

    Sascha_Thiel schrieb:

    Sorry, aber meiner Meinung nach ist dein Code sehr Praxisfremd.
    Wer;schreibt;seine;Texte;mit;Semicolon;getrennt???
    Wenn du statt der Abfrage auf (ASCII 32 == Space) vergleichst wäre es besser.

    Sascha, ich glaube du hast das Prinzip dieses excluders nicht verstanden. Es geht hier nicht darum, den Datentext zu sehen, sondern er ist z.B in einer Datenbank abgelegt. Zudem musst du die Trennzeichen nicht manuell eingeben, das macht dein Programm selber. (z.B):

    ofstream out ("beispiel.txt");
    out<<wort1<<";"<<wort2"<<;"<<endl;
    

    Würde ich deine Idee mit den Leerzeichen umsetzen, würde es keinen Sinn geben, weil z.B ein Name aus zwei oder mehreren Wörtern bestehen kann. Somit weis das Programm nicht, was zu was gehört. Darum das Trennzeichen.

    Nun zum anderen:

    Wenn das ein Header ist, gehört kein "using namespace std" rein (meiner Meinung nach gehört das nirgends rein, aber das ist ein anderes

    Das ist deine Meinung. Meinungen sind immer anders. Somit kann ich nicht wegen dir das using namespace weglassen.

    Das ist eine Funktion und was eine Funktion ist, soll auch so geschrieben sein. Warum diese Klasse?

    Wozu denn überhaupt OOP?! Deiner Aussage nach würde es somit keine OOP geben. Zudem ist das wieder deine persönliche Meinung, kein Muss oder sonst was. Zudem bietet OOP mehr Überblick.

    Der Name "excluder" sagt mir, daß etwas exkludiert wird. Du sagst aber richtigerweise, daß der String in Einzelteile zerlegt wird. Also eher "splitter" oder so.

    Ja das ist richtig. Splitter und excluder haben den selben Sinn. Sieh mal im Wörterbuch nach. "exclude= absondern " "splitting = spaltung" .

    Zum finden eines Zeichens in einem String oder auch eines anderen Containers dient der find-algorithmus. Oder aber die find-Methoden aus std::string

    Da hast du Recht. Wenn es dir so recht ist:

    string excluder(string &source,char del,int pos)
    {
       int stbeg=-1;
       while(pos--) stbeg=source.find(del,stbeg)+1;
       return source.substr(stbeg,source.find(del,stbeg)-stbeg);
    }
    

    Statt std::string könntest Du daraus ein Template machen, so das man auch andere std::basic_string-Klassen verwenden kann.

    Mit Templates habe ich noch keine Erfahrungen gemacht.

    Korrigier mal die Einrückung

    Danke für den netten Hinweis. Nur Leider hatte ich um eins in der Nacht keine Zeit und keine Lust mehr gehabt, einen 20 - zeiligen Beispielcode einzurücken.

    MFG mikey





  • mikey schrieb:

    Wenn das ein Header ist, gehört kein "using namespace std" rein (meiner Meinung nach gehört das nirgends rein, aber das ist ein anderes

    Das ist deine Meinung. Meinungen sind immer anders. Somit kann ich nicht wegen dir das using namespace weglassen.

    Es macht aber Sinn es nicht in den Header zu packen, weil sonst bei jedem der den Header includiert, auch der Namespace offen ist.



  • Nur weil du eine Klasse benutzt heißt das überhaupt nicht das du objekt orientiert programmierst.



  • mikey schrieb:

    Wenn das ein Header ist, gehört kein "using namespace std" rein (meiner Meinung nach gehört das nirgends rein, aber das ist ein anderes

    Das ist deine Meinung. Meinungen sind immer anders. Somit kann ich nicht wegen dir das using namespace weglassen.

    Nicht alle Meinungen sind gleichwertig. Vielleicht solltest du mal die Begründungen pro/kontra "using ..." in Headern gegenüberstellen.

    mikey schrieb:

    Das ist eine Funktion und was eine Funktion ist, soll auch so geschrieben sein. Warum diese Klasse?

    Wozu denn überhaupt OOP?! ...

    Wozu deine Funktion in Objekt zwängen?

    mikey schrieb:

    Der Name "excluder" sagt mir, daß etwas exkludiert wird. Du sagst aber richtigerweise, daß der String in Einzelteile zerlegt wird. Also eher "splitter" oder so.

    Ja das ist richtig. Splitter und excluder haben den selben Sinn. Sieh mal im Wörterbuch nach. "exclude= absondern " "splitting = spaltung" .

    Wenn du deinen Code der Allgemeinheit zur Verfügung stellen möchtest wäre es durchaus sinnvoll auf deine Privatinterpretation der englischen Sprache zu verzichten.



  • Um jetzt mal den letzten Punkt anzusprechen. Sicherlich mag es besser sein, deutsche Namen anzuwenden. Jedoch basiert die Programmierung sowie der allgemeine Sprachgebrauch auf Englisch. Und mit "Allgemeinheit" sind sowohl die Deutschen als auch besonders die Englischsprachigen als Zielgruppe anzusehen. Zudem haben sehr viele Leute ihre Sources mit Englischen Namen versehen. Und wenn man schon C++ programmiert, setzte ich ein Mindestmaß an Englischkentnissen voraus, wodurch es durch so ein einfaches Wort wie "excluder", dass sich sowieso aus der deutschen Sprache herleiten lässt, keine Probleme geben dürfte.

    Ich könnte ja auch auf Deutsch "Exkluder" schreiben, jedoch lässt sich das dann auch als "Splitter" intepretieren.



  • Es geht nicht darum, dass hier jemand nicht des Englischen mächtig ist. Excluder würde auch für einen Engländer völlig Banane klingen.



  • Genau das ist der Punkt. Excluder ist nämlich ein englisches Wort, das aber genauso gut Deutsche verstehen. Genauso wie "hello" und "hallo". Aber ich möchte die Diskussion hier nicht noch ausweiten, da dies ein C++ Forum ist, und nicht ein Diskussionsforum.



  • Achja, irgendwie mache ich in meinem Quellcode mittlerweile schon fast alles falsch: "Zweckentfremdet", "Objektorientiert", "Englischsprachig", "Mangelhaft (was sich jedoch nicht ausschliesen lässt :-D) und noch ein paar Dinge. Aber anstatt mal zu schreiben, hey, das ist zwar ganz nett, aber du könntest das und das besser machen... Immerhin bin ich ein Anfänger (was ich bis hierhin noch nicht erwähnt habe...) und ich finde für diesen Code ist es ganz akzeptabel, natürlich sind noch viele Dinge besser zu machen, was ich ja auch nicht bestreite, aber mittlerweile werden mir ganz banale Dinge vorgeworfen, die doch überall vorkommen. Wer nicht in der Lage ist "exlcuder" zu verstehen, der solls doch einfach lassen. Hätte ich meinetwegen andere kompliziertere Funktionen und Namen, würde ich sie natürlich verständlich benennen. Dann lass ichs halt bleiben. Ihr kritisiert meinen Code zum Teil auch noch leicht abwärtend, immer nur Kritik, blabla, aber was ich mal gut gemacht habe, das schreibt hier keiner. Und es kann mir auch genausogut keiner sagen, dass in diesem Code nichts gutes wäre. 👎



  • mikey schrieb:

    Und wenn man schon C++ programmiert, setzte ich ein Mindestmaß an Englischkentnissen voraus, wodurch es durch so ein einfaches Wort wie "excluder", dass sich sowieso aus der deutschen Sprache herleiten lässt, keine Probleme geben dürfte.

    Ja, das ist ganz genau der Punkt. Dir scheint einfach nicht klar zu sein was "exclude" heisst.



  • Wenn du hier Code postest, dann musst du mit Kritik rechnen. Da lernt man als Anfänger draus. Zum Beispiel ist es nicht objektorientiert, wenn man jede kleine Hilfsfunktion in eine eigene Klasse packt. Auch den Hinweis auf das using im Header hast du erstmal ignoriert statt zu überlegen warum das nicht so gut sein könnte. Im übrigen finde ich deine Erklärung mit dem Excluder mehr als schwammig. Aber was solls...



  • Ich habe nicht jede kleine Hilfsfunktion in eine Klasse gepackt, im Gegenteíl, es geht mir darum, dass ich meinen eigentlichen Programmcode sauber halten kann, und nicht diese wirren Zeilen einfügen, die den Code nur unübersichtlich machen. Und ich weis auch nicht, wie ich eine Header OHNE Klasse programmieren soll.......


Anmelden zum Antworten