Zahlenwerte aus einem String "filtern"



  • string text = "N142X-342765Y31357Z36970G00";
    
    size_t x_start = text.find("X"), y_start = text.find("Y"),
           z_start = text.find("Z");
    
    cout << text.substr(x_start + 1, y_start - x_start - 1);
    

    Natürlich die find-Sachen auf npos prüfen.

    http://www.cppreference.com/cppstring/substr.html
    http://www.cppreference.com/cppstring/find.html



  • Oder du bastelst dir eine Methode, die den String flexibel zerlegt.
    Stelle ich mir ungefähr so vor:

    bool ExtractCoords( string text, map<char,double>& coords )
    {
        // Zerlegt hier den String in die einzelnen Teile und schreibt
        //   zu jedem darin vorkommenden Buchstaben den zugehörigen Zahlenwert
        //   in die map.
    }
    
    ...
    
    string text = "N142X-342765Y31357Z36970G00";
    map<char,double> coords;
    if ( ! ExtractCoords( text, coords ) )
    {
        // Fehler
    }
    else
    {
        // coords['X'] beinhaltet die x-Koordinate usw.
    }
    


  • std::string text = "N142X-342765Y31357Z36970G00";
    
    void extract_coords(const std::string& string, double& x, double& y, double& z)
    {
        std::size_t pos_x = string.find_first_of('X');
        std::size_t pos_y = string.find_first_of('Y', pos_x);
        std::size_t pos_z = string.find_first_of('Z', pos_y);
        std::size_t pos_end = string.find_first_not_of("0123456789", pos_z);
        if (pos_x == std::string::npos || pos_y == std::string::npos || pos_z == std::string::npos)
            throw std::logical_error("Invalid string!");
    
        std::stringstream ss(string.substr(pos_x + 1, pos_y));
        ss >> x;
        ss.clear();
        ss.str("");
        ss << string.substr(pos_y + 1, pos_z);
        ss >> y;
        ss.clear();
        ss.str("");
        ss << string.substr(pos_z + 1, pos_end);
        ss >> z;
    }
    

    ist aber nicht die kürzeste Lösung 😞



  • Ich bin nicht besonders gut mit der STL, aber das hier geht auch:

    void ExtractCoords( string text, map<char,double>& coords )
    {
    	char last_char = '\0';
    	for ( size_t i=0, last=-1, len=text.length(); i<len; ++i )
    	{
    		if ( isalpha( text[i] ) )
    		{
    			char c = text[i];
    			if ( last != -1 )
    			{
    				text[i] = '\0';
    				coords[last_char] = atof( text.c_str()+last );
    			}
    			last_char = c;
    			last = i+1;
    		}
    	}
    	if ( last != -1 )
    		coords[last_char] = atof( text.c_str()+last );
    }
    

    edit: Nur aus Interesse, wie kann man das elegant mit der STL machen 😕



  • ok, funktioniert jetzt einigermasen, jetzt versuche ich
    das alles in eine Funktion zu packen um diese dann in eine
    externe Headerdatei auszulagern, aber irgendwie will´s nich so
    recht funktionieren.

    Kann ich der Funktion ein String übergeben und als
    Rückgabewert eine double erhalten ??

    Ich bekomme als Rückgabewerd x_koord immer "999999999999999"
    so als wenn der String überhaupt nicht bearbeitet wird !!

    #include <cstdlib>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    double x_filter(string);
    
    int main(int argc, _TCHAR* argv[])
    {
    	string programmzeile;								// Variablendeklaration
    	double x_koord;
    
    	cout << "NC-Programmzeile eingeben: ";				// Textzeile einlesen:
    	getline ( cin, programmzeile);
    
    	x_koord = x_filter(programmzeile);
    
    	cout.precision(3);									// Genauigkeit auf 3 Stellen setzen
    	cout << showpoint << fixed << showpos				// X-Koordinate ausgeben mit 3 Nachkommastellen und
    		 << "\n\nX-Koordinate: " << x_koord << "\n\n";	// positiven Vorzeichen
    
    	system("PAUSE");
    	return 0;
    }
    
    double x_filter(string)
    {
    	string x_edit;
    	double x_koord;									// Programmzeile in die Variable x_edit kopieren
    	int xanfang = x_edit.rfind("x");				// Anfang der X-Koordinate suchen und X-Buchstabe entfernen
    	if (xanfang != std::string::npos)				// Wenn kein X vorhanden ist an Verzweigungsende Springen
    	{	xanfang++;
    		x_edit = x_edit.erase(0,xanfang);				// Zeilenanfang bis X-Koordinate löschen
    		int satzlaenge = x_edit.length()-1;				// Länge der restlichen Zeile bestimmen
    		int xende = x_edit.rfind("y");					// Anfang der Y-Koordinate suchen
    		if (xende != std::string::npos);				// Wenn kein Y vorhanden ist nach Z-Koordinate suchen
    			else xende = x_edit.rfind("z");
    		if (xende != std::string::npos);				// Wenn auch kein Z vorhanden ist nach G Suchen
    			else xende = x_edit.rfind("g");
    			if (xende != std::string::npos);			// Wenn auch kein G vorhanden ist dann Zeilenende nehmen
    			else xende = satzlaenge+1;
    		x_edit = x_edit.erase(xende,satzlaenge);		// von Ende der X-Koordinate bis Zeilenende löschen
    		x_koord = atof (x_edit.c_str());				// X-Koordinate von String in Double umwandeln
    		x_koord = x_koord / 1000;}						// 1000stel in ganze MM umrechnen
    	else x_koord = 999999999999999;					// Wenn kein X vorhanden ist setz den wert auf 999999999999999
    	return x_koord;
    }
    

    Was hab ich da falsch gemacht ??

    Es geht mir jetzt nur um den richtigen Rückgabwert, die
    Zerlegung des String´s werde ich dann noch umschreiben, entsprechend
    euren vorschlägen !!



  • 'x' != 'X' 😉

    if(x_edit.find('x') != string::npos || x_edit.find('X') != string::npos)
    {
    ...
    }
    else ... //9999999
    


  • Badestrand schrieb:

    edit: Nur aus Interesse, wie kann man das elegant mit der STL machen 😕

    Vielleicht so:

    void ExtractCoords( string text, map<char,double>& coords )
    {
    
    	char last_char = 0;
    	string::iterator pos = text.end(), last_pos = text.end();
    
    	while ( (pos = find_if(text.begin(),text.end(),isalpha)) != text.end() )
    	{ 
    		if( pos == text.begin() ) 
    		{ 
    			last_char = *pos;
    			last_pos = pos; 
    			*pos = 0; 
    
    			continue; 
    		}
    
    		stringstream sstr("");
    		copy(last_pos+1,pos,ostream_iterator<char>(sstr)); //da es blöderweise kein string::substr für iteratorn gibt
    
    		double val = 0;
    		sstr >> val;
    
    		coords[last_char] = val;
    
    		last_char = *pos;
    		last_pos = pos;
    		*pos = 0;
    	}
    
    }
    

    Edit: gcc aus C::B will die find_if Anweisung nicht kompilieren 😡



  • KasF schrieb:

    copy(last_pos+1,pos,ostream_iterator<char>(sstr)); //da es blöderweise kein string::substr für iteratorn gibt
    

    😕 Meinst Du folgendes?

    string newstring(last_pos + 1, pos);
    


  • KasF schrieb:

    Edit: gcc aus C::B will die find_if Anweisung nicht kompilieren 😡

    Das liegt daran dass isalpha dort wohl ein Makro ist (und imho auch sein darf). Zusätzlich könnten Dir die Überladungen aus <locale> einen Strich durch die Rechnung machen (betrifft alle Compiler).



  • LordJaxom schrieb:

    KasF schrieb:

    Edit: gcc aus C::B will die find_if Anweisung nicht kompilieren 😡

    Das liegt daran dass isalpha dort wohl ein Makro ist (und imho auch sein darf).

    AFAIK ist 'isalpha' sowieso nur mit 'int'-Parametern definiert, d.h. die Signatur passt hier eh nicht.



  • Konrad Rudolph schrieb:

    😕 Meinst Du folgendes?

    string newstring(last_pos + 1, pos);
    

    🙄 🙄
    Wollte eigentlich sstr nen substring übergeben, aber habe voll vergessen, dass man einen string auch so konstruieren kann.

    LordJaxom schrieb:

    Das liegt daran dass isalpha dort wohl ein Makro ist (und imho auch sein darf). Zusätzlich könnten Dir die Überladungen aus <locale> einen Strich durch die Rechnung machen (betrifft alle Compiler).

    Achso, danke.

    bool isAlpha(char c)
    {
        return isalpha(c);
    }
    ...
    find_if(text.begin(),text.end(),isAlpha)
    ...
    stringstream sstr( string(last_pos + 1,pos) );
    


  • Du musst aber, glaube ich, noch ne Kleinigkeit ändern, 'G' wird noch nicht erfasst (bei mir jedenfalls nicht). Das Problem hatte ich auch erst :p

    ^Und ich hab meinen Code nochmal verändert, 'text' kann ich ja verändern wie ich will :)^



  • Badestrand schrieb:

    Du musst aber, glaube ich, noch ne Kleinigkeit ändern, 'G' wird noch nicht erfasst (bei mir jedenfalls nicht). Das Problem hatte ich auch erst :p

    bool isAlpha(char c)
    {
        return isalpha(c);
    }
    
    void ExtractCoords( string text, map<char,double>& coords )
    {
    
        char last_char = 0;
        string::iterator pos = text.end(), last_pos = text.end();
    
        while ( (pos = find_if(text.begin(),text.end(),isAlpha)) != text.end() )
        {
            if( pos == text.begin() )
            {
                last_char = *pos;
                last_pos = pos;
                *pos = 0;
    
                continue;
            }
    
            stringstream sstr( string(last_pos + 1,pos) );
    
            double val = 0;
            sstr >> val;
    
            coords[last_char] = val;
    
            last_char = *pos;
            last_pos = pos;
            *pos = 0;
        }
    
         stringstream sstr( string(last_pos+1,text.end()) );
    
         double val = 0;
         sstr >> val;
    
         coords[last_char] = val;
    
    }
    

    🙂
    Das kann man aber bestimmt noch eleganter lösen, vielleicht zaubert ja Konrad ne rekursive Lösung ...



  • Und nochmal was gefrickelt:

    bool isAlpha(char c)
    {
        return isalpha(c);
    }
    
    template<class T, class S>
    T lexical_cast(const S& val)
    {
        stringstream sstr("");
        T newval;
        if( !( sstr << val && sstr >> newval ) )
           throw bad_cast();
    
        return newval;
    }
    
    void ExtractCoords( string text, map<char,double>& coords )
    {
    
        typedef string::iterator sIT;
    
        struct helpFunc {
            void operator()(char& last_char, sIT& pos, sIT& last_pos)
            {
                last_char = *pos;
                last_pos = pos;
                *pos = 0;
            }
        };
    
        char last_char = 0;
        sIT pos = text.end(), last_pos = text.end();
    
        while ( (pos = find_if(text.begin(),text.end(),isAlpha)) != text.end() )
        {
            if( pos == text.begin() )
            {
                helpFunc()(last_char,pos,last_pos);
                continue;
            }
    
            coords[last_char] = lexical_cast<double>( string(last_pos + 1,pos) );
    
            helpFunc()(last_char,pos,last_pos);
        }
    
         coords[last_char] = coords[last_char] = lexical_cast<double>( string(last_pos+1,text.end()) );
    
    }
    


  • hehe :p:

    void ExtractCoords( string text, map<char,double>& coords )
    {
    	for ( int i=text.length()-1; i>=0; --i )
    	{
    		if ( isalpha( text[i] ) )
    		{
    			coords[ text[i] ] = atof( text.c_str()+i+1 );
    			text[i] = '\0';
    		}
    	}
    }
    


  • Noch ein Nachtschwärmer 🙂

    Elegante Idee von Rückwärts durchzulaufen. Wenn die Sonne aufgeht, schreibe ich meins um ...



  • geSTL'te Version:

    void ExtractCoords( string text, map<char,double>& coords )
    {
        string::reverse_iterator pos = text.rend();
    
        while ( ( pos = find_if(text.rbegin(), text.rend(), isAlpha) ) != text.rend() )
        {
            size_t dis = distance(pos,text.rend());
    
            coords[*pos] = lexical_cast<double>( text.substr(dis) );
            text.erase(dis-1);
        }
    }
    

Anmelden zum Antworten