Anzeige:
Ergebnis 1 bis 6 von 6

Thema: C++ string-parsen

  1. #1
    Registrierter Benutzer
    Registriert seit
    22.11.2007
    Beiträge
    8

    C++ string-parsen

    Hi,

    folgende Situation.

    Ich brauche für ein Programm ein config-file.
    Dort verwende ich ein Keyword um den danach stehen Teil als Pfadangabe einzulesen (Bsp.: keyword = "/home/user/.conf/needDir/").

    Dazu hab ich mal bischen rumgespielt (und das funktioniert auch):

    Code:
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    
    int main()
    {
    	int lastPos; // of find-string
    	
    	string full = "keyword test!";
    	string searchFor = "keyword";
    	string temp = "";
    
    	string::size_type loc = full.find( searchFor.c_str(), 0 );
    
    	if( loc != string::npos )
    	{
    		lastPos = full.find_last_of( searchFor.c_str() );
    
    		temp = full.substr( lastPos + 2 );
    
    		int newSize = temp.size();
    
    		temp.erase( newSize );
    
    		cout << temp << "\n";
    
    	}
    	else
    	{
    		cout << "\n\tELSE\n";
    	}
    
    	return 0;
    }
    Ausgabe ist dann wie gewollt "test!" (ohne "").

    Jetzt hab ich das ganze in das gewollte Programm übernommen (und hier funktioniert es nicht).

    Code:
    int readConfigFile()
    {
    	int returnValue = -1; // -1 => error!
    	
    	string configFile = "./obrw.conf";
    	string configStrings[1024];
    	ifstream inputStream;
    	string s;
    	inputStream.open( configFile.c_str() );
    
    	int readedLines = 0; // einlesen der Vorhandenen Zeilen im Configfile
    
    	if( !inputStream )
    	{
    		cout << "Error opening input stream\n";
    		exit(1);
    	}
    	else
    	{
    		while( !inputStream.eof() )
    		{
    			getline( inputStream, s );
    			configStrings[readedLines] = s;
    			readedLines++;
    		}
    		inputStream.close();
    	}
    
    	int lastPos; 				// lastPos of parseword => 7 wäre hier richtig
    	string parseWpDir = "wpDir =";		// keyword for wallpaperDir
    	string tempString = "";				// includes the parsed strings
    
    	cout << "lines : " << readedLines << "\n";
    
    	for(int i = 0; i < readedLines; i++)
    	{
    		// at this position we are searching for parseString (parseWpDir)
    		string::size_type loc = configStrings[i].find( parseWpDir.c_str(), 0);
    
    		// string::npos if parseWpDir doesn't exist
    		if( loc != string::npos )
    		{
    			cout << "parse : " << parseWpDir << "\n";
    			cout << "configStrings[i] : " << configStrings[i] << "\n";
    
    
    			lastPos = configStrings[i].find_last_of( parseWpDir.c_str() );
    
    
    			cout << "lastPos : " << lastPos << "\n";
    
    
    			tempString = configStrings[i].substr(lastPos +2);
    
    
    			int newSize = tempString.size();
    			tempString.erase( newSize - 1 ); // holt das hinter " aus dem String
    
    
    			cout << "after erase: " << tempString << "\n";
    
    			returnValue = 999;
    		}
    	}
    
    	return returnValue;
    }
    Ausgabe:

    lines : 3
    parse : wpDir =
    configStrings[i] : wpDir = "/home/user/.config/wallpapers/"
    lastPos : 39
    after erase: /

    lastPos müsste nun aber eigentlich den Wert 7 haben.
    Nun ja, ich versteh es nicht mehr wirklich.
    Vielleicht übersehe ich ja auch nur eine Kleinigkeit, oder so.

    Wäre schön, wenn ihr euch mal kurz mit dem code befassen könntet und vielleicht sogar den Fehler findet.

    gruß Datalux

  2. #2
    Registrierter Benutzer
    Registriert seit
    23.05.2004
    Beiträge
    592
    Du solltest noch einmal nachlesen, was std::string::find_last_of macht. Die Funktion weicht, so wie ich das sehe, in ihrem Verhalten von deiner Erwartung ab.

    Noch ein paar Anmerkungen:
    1. Du musst nicht so oft string::c_str verwenden. Die meisten String-Funktionen sind doch eh überladen.
    2. Es wäre vermutlich von Vorteil, wenn du deine Fehlerbehandlung ausbauen würdest, so das deine Funktion z.B. erkennen kann wenn nach einem "Keyword" in deiner Config-Datei gar kein Datum mehr folgt.
    3. Deine Abfrage des Dateiendes ("while( !inputStream.eof() )") ist nicht robust. Du solltest besser prüfen, ob die letzte Eingabeoperation (also getline z.B.) fehlschlug. Wenn ja, dann könnte eof der Grund dafür sein.
    4. Du kannst die Lesbarkeit deiner Funktion unter Umständen verbessern, indem du Variablen in den innersten möglichen Scope packst. Speziell meine ich deine "temp" Variablen. Die können in das "if" hinein, weil du sie außerhalb eh nicht brauchst. Aber Urteile selber.
    5. Wenn du Puffer fester Größe verwendest ("string configStrings[1024]"), dann solltest du unbeding sicherstellen das du sie niemals außerhalb ihrer Größen indizierst. Also prüfe ob du eventuell mehr als 1024 Zeilen liest.

  3. #3
    Registrierter Benutzer
    Registriert seit
    22.11.2007
    Beiträge
    8
    hi,

    ich beziehe mich einfach schonmal zu deinem post (schafft Klarheit)

    zu 1: hatte oft mal nen Fehler, wenn ich einen String direkt übergeben habe und so hab ich es mir angewöhnt.

    zu 3: mhhh, ok (obwohl ich meine, dass auch ein leeres file eingelesen wird (leerer String), aber trotzdem müsste es ja noch funktionieren, da der pfad String an position i = 1 steht + es auch funktioniert, wenn ich lastPos manuel auf 7 setze.
    Werde es aber trotzdem in die fix-liste zur Überprüfung nehmen.

    zu 4: stimmt eigentlich

    zu 2 und 5: Programm arbeitet mom nur für mich und ich stecke mom halt bei der ConfReadFunktion fest. Das Array ist z.B. momentan noch feste größe, da ich noch nicht soviel in C++ programmiert habe und schauen möchte, dass das Einlesen ordnungsgemäß funktioniert (aber steht halt schon in der fix-list, da das ja auch ein mieser Fehler wäre, der nicht auf jedem System zu finden ist ).

  4. #4
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Wenn deine Datei im Muster
    Code:
    key = value
    aufgebaut ist, wäre es vermutlich einfacher, nur nach dem "=" zu suchen, also

    Code:
    string::size_type pos = line.find('=');
    if (pos != string::npos)
    {
        string key = line.substring(0, pos);
        string value = line.substring(pos + 1);
    
        // dann eventuell noch Leerzeichen entfernen
    }
    else
    {
        // ungültige Zeile
    }
    Wenn jeder Key eindeutig ist, kann man die Werte gleich direkt in einer Map ablegen

    Code:
    map<string, string> config;
    
    config.insert(make_pair(key, value));
    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  5. #5
    Registrierter Benutzer
    Registriert seit
    22.11.2007
    Beiträge
    8
    ok und dankeschön

    Hab den Code jetzt mal funktionsfähig abgewandelt (ohne map-funktion, aber muss ich mir wohl mal anschauen ).

    axo, Config-Muster: wpDir = "/pfad/zum/verzeichnis/"
    (erklärt den value.erase()-Aufruf in :167 und :168)


    Code:
    int readConfigFile()
    {
    	int returnValue = -1; // -1 => method-error!
    	
    	string configFile = "./obrw.conf";
    	string configStrings[1024];
    	ifstream inputStream;
    	string s;
    	inputStream.open( configFile.c_str() );
    
    	int readedLines = 0;
    
    	if( !inputStream )
    	{
    		cout << "Error opening input stream\n";
    		exit(1);
    	}
    	else
    	{
    		while( !inputStream.eof() )
    		{
    			getline( inputStream, s );
    			configStrings[readedLines] = s;
    			readedLines++;
    		}
    		inputStream.close();
    	}
    
    	// keywords to parse
    	string parseWpDir = "wpDir ";		// keyword for wallpaperDir
    
    	for(int i = 0; i < readedLines; i++)
    	{
    		// at this position we are searching for possible stringpart ( '=' )
    		string::size_type loc = configStrings[i].find( '=' );
    
    		// string::npos if '=' doesn't exist in configStrings[i] (!!!  if != x))
    		if( loc != string::npos )
    		{
    			string key = configStrings[i].substr( 0, loc );		
    			string value = configStrings[i].substr( loc + 1 );
    
    			// is wpDir-pathVar?
    			if(key == parseWpDir)
    			{
    				//here we could start a value-check (regular-expression => injections possible?)
    
    				value.erase( 1, 1 );					// first " 
    				value.erase( value.size() - 1 );		// last "
    				dirName = value;						// set globalVar dirName
    
    				returnValue = 999;						// returnValue for correct run
    			}
    			else										
    			{
    				// error-msg if keyword doesn't match
    				cout << "Error in config (wpDir isn't ok)\n";
    			}
    		}//if ( loc != string::npos )
    	}//for
    
    	return returnValue;
    }
    Geändert von datalux (22-11-2007 um 16:07 Uhr)

  6. #6
    Registrierter Benutzer
    Registriert seit
    22.11.2007
    Beiträge
    8
    Zitat Zitat von locus vivendi Beitrag anzeigen
    Du solltest noch einmal nachlesen, was std::string::find_last_of macht. Die Funktion weicht, so wie ich das sehe, in ihrem Verhalten von deiner Erwartung ab.
    Argh ...

    Hab mir die Referenz gerade nochmal angeschaut und das Brett mal abgeschaft ...

    Klar, den letzten, übereinstimmenden char ...

    und mit wpDir findet er ihn bei mir in wallpaper vorher in Position 39.

    omg, der Wald und die Bäume ...

    Dankeschön nochmal

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •