Unzufrieden mit Funktion (Strings)



  • Hi,

    ich wollte mal eine Funktion schreiben, die mir die Befehle in einer HL2-Config Datei durchließt, zählt und einzeln ausgibt.

    In so einer Datei könnte z. B. soetwas stehen:

    var xxx 4 ; bind "xxx" "hallo" ; echo "hallo ; du da"
    

    Befehle mit Argumenten können durch ein ";" getrennt werden, jedoch nur, wenn diese sich nicht in einem String befinden.

    Soweit sogut. Daraufhin hab ich mal diese Funktion geschrieben:

    void count_commands (const std::basic_string<TCHAR>& value)
    {
        bool in_string = false;
    
        for (unsigned long i = 0, position = 0, count = 0; i < value.size (); ++i)
        {
            if (value[i] == _T ('\"'))
                in_string ^= true;
    
            if (value[i] == _T (';') && in_string)
                continue;
    
            if (value[i] == _T (';') || i == value.size () - 1)
            {
                if (i == value.size () - 1)
                    ++i;
    
                std::wcout << count++ << _T (": ") << value.substr (position, i - position) << std::endl;
                position = i + 1;
            }
        }
    }
    

    Die Funktion läuft erste Sahne, jedoch gefällt sie mir nicht besonders. Vorallem das letzte if, wo ich mit value.size () - 1 das 'i' abfrage, damit er nicht den letzten Befehl auslässt. Auch das letzte if wo ich 'i' inkrementiere gefällt mir nicht so recht, aber wenn ich es weglasse, wird das letzte Zeichen übersprungen.

    Kennt da jemand eine "bessere" bzw. "schönere" Lösung?

    Hier noch meine Main-Funktion.

    int main (void)
    {
        count_commands (_T ("var xxx 4 ; bind \"xxx\" \"hallo\" ;echo \"hallo ; du da\""));
    }
    

    Danke im voraus 🙂



  • boost::tokenizer kann soweit ich weiß auch mit Anführungszeichen umgehen.
    Dann musst du nur noch den tokenizer mit dem string füttern (bei ; spliten) und du bekommst viele einzelne kommandos zurück.



  • Wollte eigentlich nicht extra auf Zusatzlibs zurückgreifen, sondern eher nur die STL benutzen.



  • hm.. ich versuch ma was ausm stehgreif

    int count_commands(const string& command)
    {
      int num = 0;
      for(int i = 0; i < command.size(); i++)
      {
        char c = command[i];
        if(c == '\"')
        {
          size_t f = command.find('\"', i+1);
          if(f == command.npos)
            throw std::runtime_error("Fehlerhaftes Kommando!") // es fehlt passendes gegenstück zu "
          i = f;
        }
        else if(c == ';') // ; außerhalb von ""
          num++;
      }
    
      return num;
    
    }
    

  • Mod

    struct command_counter
    {
        command_counter() : s_(), in_string_( false ), count_( 0 ) {}
        int print()
        {
            if ( !in_string_ && !s_.empty() )
            {
                std::wcout << count_++ << L": " << s_ << std::endl;
                s_.clear();
            }
            return count_;
        }
        void operator()(wchar_t c)
        {
            if ( !in_string_ && c == L';' )
                print();
            else
            {
                in_string_ = in_string_ == ( c != L'\"' );
                s_.push_back( c );
            }
        }
        std::string s_:
        bool in_string_;
        int count_;
    };
    int count_commands(const std::wstring& value)
    {
        return std::for_each( value.begin(), value.end(), command_counter() ).print();
    }
    

    ist eigentlich auch nicht besser...


Anmelden zum Antworten