Splitten von Strings mit verschiedenen Delimetern



  • Hallo,

    ich habe einen "großen" String aus denen ich mehrere gewinnen möchte:

    string line = "!=\"abcd!#efg\" !\"ABCDEFGHAG!/8765438\" !\"This !/[isanotherstring]?but nobody cares78\" !=\"again a string with equal sign and exclamation mark\"";
    

    Die Delimeter sind !" oder !=".

    Da innerhalb der Substrings auch Ausrufezeichen vorkommen können kann ich nicht einfach das Ausrufezeichen als Trenner nehmen ansonsten wäre der Substring kaputt.

    Ich habe folgendes Beispiel nachgebaut und der Code lässt sich ausführen

    #include <iostream>
    #include <string>
    #include <boost/regex.hpp>
    #include <boost/algorithm/string.hpp>
    #include <boost/algorithm/string/regex.hpp>
    #include <vector>
    
        using namespace std;
        using namespace boost;
    
        std::string line;
    
    ///////////// Create vector to store matrix
        std::vector< std::vector<string> > vec_line;
        // Create temp vector to create "rows"
        vector<string>vec_string_temp;
    
    string add2vec_ele(string firste, string line)
    {
    
        // Add row
        vec_string_temp.push_back(firste);
        boost::algorithm::split_regex( vec_string_temp, line, regex( "(!=\"|!\")" ) ) ;
        // store row in vec_line
        vec_line.push_back(vec_string_temp);
        vec_string_temp.clear();
    return string();
    }
    
    int main()
    {
        string firste = "KeyWord";
        string line = "!=\"abcd!#efg\" !\"ABCDEFGHAG!/8765438\" !\"This !/[isanotherstring]?but nobody cares78\" !=\"again a string with equal sign and exclamation mark\"";
        add2vec_ele(firste,line);
    
        // print all elements
        for (unsigned int i = 0; i < vec_line.size(); i++)
        {
            std::cout << "Vector line: " << i << " ";
            for (unsigned int j = 0; j < vec_line[i].size(); j++)
            {
                std::cout << " Col: " << j << " " << vec_line[i][j];
            }
            std::cout << endl;
        }
    }
    

    Damit bekomme ich als Output:

    Vector line: 0  Col: 0  Col: 1 abcd!#efg"  Col: 2 ABCDEFGHAG!/8765438"  Col: 3 This !/[isanotherstring]?but nobody cares78"  Col: 4 again a string with equal sign and exclamation mark"
    

    Ich bräuchte aber die führenden !=" bzw. !"

    Vector line: 0  Col: 0  Col: 1 !="abcd!#efg"  Col: 2 !"ABCDEFGHAG!/8765438"  Col: 3 !"This !/[isanotherstring]?but nobody cares78"  Col: 4 !="again a string with equal sign and exclamation mark"
    

    boost::algorithm::split_regex scheint also die Delimeter zu entfernen und mein Ziel damit also unmöglich zu machen. Ich habe mir auch andere split Methoden angesehen aber nicht wirklich einen Weg gefunden das damit zu realisieren.

    Habt Ihr eine Idee wie ich das am besten Lösen kann? Das einzige was ich noch sehe ist irgendwie mir zu merken bei welchem Substring !=" oder !" hin muß und es entsprechend nach dem füllen des vectors einzufügen.



  • Kannst Du nochmal bitte kurz einen String zeigen original und dann danach wie Du es haben willst oder deine Anfuehrungszeichen reparieren in deinem unteren Beispiel?

    Edit: Mit anderen Worten deine Zeichen sind keine Delimiter sondern sind Information die erhalten bleiben sollen?



  • Ziemlich grausig ... aber ... sowas?

    #include <cstdlib>
    #include <vector>
    #include <string>
    #include <iostream>
    
    int main()
    {
    	std::string line = "!=\"abcd!#efg\" !\"ABCDEFGHAG!/8765438\" !\"This !/[isanotherstring]?but nobody cares78\" !=\"again a string with equal sign and exclamation mark\"";
    
    	std::vector< std::string > v;
    
    	auto begin = line.begin();
    	auto end = begin;
    
    	do {
    		while( begin != line.end() && *begin != '!' )
    			++begin;
    
    		if( begin == line.end() )
    			break;
    
    		end = begin;
    
    		if( ++end != line.end() && *end == '=' )
    			++end;
    
    		if( end != line.end() && *end++ != '"' ) {
    			begin = end;
    			continue;
    		}
    
    		while( end != line.end() && *end != '"' )
    			++end;
    
    		v.push_back( std::string( begin, ++end ) );
    
    		begin = end;
    	} while( end != line.end() );
    
    	for( auto &i : v )
    		std::cout << i << '\n';
    	std::cout.put( '\n' );
    }
    


  • Wie wär's mit look-ahead?

    boost::algorithm::split_regex( vec_string_temp, line, regex( "(?<!^)(?:(?=!=\")|(?=!\"))" ) ) ;
    

    Ansonsten: wofür ist der Parameter "firste" gut?

    Ein Perl-Freund 🙂



  • string line = "!=\"abcd!#efg\" !\"ABCDEFGHAG!/8765438\" !\"This !/[isanotherstring]?but nobody cares78\" !=\"again a string with equal sign and exclamation mark\"";
    

    ich weiß nicht ob das zufall ist oder so "aber du könntest doch bei deinem beispiel auch einfach den leerschritt als trennzeichen benutzen", dann solltest du ! und != mitbekommen...

    das geht mit getline(zeile,ergebis,trennzeichen) --> trennzeichen = " " ...

    geht sicher auch ohne getline() - also eleganter ...

    lg



  • Hallo Ruvi,

    Ruvi schrieb:

    Kannst Du nochmal bitte kurz einen String zeigen original und dann danach wie Du es haben willst oder deine Anfuehrungszeichen reparieren in deinem unteren Beispiel?

    Edit: Mit anderen Worten deine Zeichen sind keine Delimiter sondern sind Information die erhalten bleiben sollen?

    Ich fürchte da ist nix kaputt mit den doublequotes, deswegen macht mich das parsen ja so wahnsinnig. Eine original line sieht etwa so aus (leicht modifiziert um klar zu machen das in dem substring doublequotes, ausrufezeichen usw. auftauchen können):

    IchBinEinKeyword !="abcd!#efg" !"ABCDEFG$%#HAG!["$getParam"]/8765438" !"This !/[!isanotherstring]?but nobody cares78" !="again a string with equal sign and exclamation mark"
    

    Das ist jetz natürlich keine Original line aus dem File, aber da sie C/C++ ähnliche synthax enthalten kann und die noch mehr Verwirrung stiften könnte hab ich das wie oben mal abgeändert. Im Prinzip ist jedes "Feld" bis auf das Keyword angeführt von einem !=" (bedeutet: Genau So!) oder einem !" (bedeutet: Muss enthalten sein!) und am Ende ein schließendes doublequote.



  • Swordfish schrieb:

    Ziemlich grausig ... aber ... sowas?

    Vielen Dank! Ich werde mir das morgen mal genau anschauen!



  • wob schrieb:

    Wie wär's mit look-ahead?

    boost::algorithm::split_regex( vec_string_temp, line, regex( "(?<!^)(?:(?=!=\")|(?=!\"))" ) ) ;
    

    Ansonsten: wofür ist der Parameter "firste" gut?

    Ein Perl-Freund 🙂

    Vielen Dank! Auch das schaue ich mir morgen mal genauer an (RegEx bis die Hirnwindungen bluten 🙂 ).

    firste ist das keyword was am anfang stehen muss in der finalen output list. Das will ich später auch nutzen als index (soweit der feuchte Traum: Ob ich das hin bekomme werde ich sehen).



  • Hallo Helpers,

    HELPERs schrieb:

    ich weiß nicht ob das zufall ist oder so "aber du könntest doch bei deinem beispiel auch einfach den leerschritt als trennzeichen benutzen", dann solltest du ! und != mitbekommen...

    Das war mein erster Versuch. Bis ich dann gemerkt habe das in den Substrings auch leerzeichen vorkommen und die substrings kaputt gehen. Wird aus meinem Beispiel leider nicht deutlich, sorry!



  • wob schrieb:

    Wie wär's mit look-ahead?

    Ich glaube das war der entscheidene Tipp!

    Hier ist für die Nachwelt der funktionierende Code:

    #include <iostream>
    #include <string>
    #include <boost/regex.hpp>
    #include <boost/algorithm/string.hpp>
    #include <boost/algorithm/string/regex.hpp>
    #include <vector>
    
        using namespace std;
        using namespace boost;
    
        std::string line;
    
    ///////////// Create vector to store matrix
        std::vector< std::vector<string> > vec_line;
        // Create temp vector to create "rows"
        vector<string>vec_string_temp;
    
    string add2vec_ele(string firste, string line)
    {
    
        // Add row
        vec_string_temp.push_back(firste);
        // Using Perl RegEx
        boost::regex ex( "(?<!^)(?:(?=!=\")|(?=!\"))", boost::regex::perl );
        // Split!
        boost::algorithm::split_regex( vec_string_temp, line, ex ) ;
        // store row in vec_line
        vec_line.push_back(vec_string_temp);
        vec_string_temp.clear();
    return string();
    }
    
    int main()
    {
        string firste = "KeyWord";
        string line = "!=\"abcd!#efg\" !\"ABCDEFGHAG!/8765438\" !\"This !/[isanotherstring]?but nobody cares78\" !=\"again a string with equal sign and exclamation mark\"";
        add2vec_ele(firste,line);
    
        // print all elements
        for (unsigned int i = 0; i < vec_line.size(); i++)
        {
            std::cout << "Vector line: " << i << " ";
            for (unsigned int j = 0; j < vec_line[i].size(); j++)
            {
                std::cout << " Col: " << j << " " << vec_line[i][j];
            }
            std::cout << endl;
        }
    }
    

    Ich muss jetzt nur noch schauen ob die Regeln im Vector auch funktionieren. Das heißt ich werd den Vector in ein File dumpen und mal ein diff drüber laufen lassen ob es mit dem Original überein stimmt. Aber erster Augenschein ist vielversprechend.

    Vielen Dank euch allen.


Anmelden zum Antworten