Prüfe auf nur erlaubte Zeichen im String



  • Hallo,

    ich habe eine Liste von erlaubten Zeichen, z.B. "a", "b", "c", " " und möchte nun überprüfen, ob ein vorliegender String ungültige Zeichen enthält, also Zeichen, die nicht in meiner Liste sind?

    Wie kann man dies effizient tun. Reguläre Ausdrücke habe ich im Standard nicht gefunden.

    Danke im Voraus für jegliche Hinweise,
    Mat.



  • Du könntest einen String "abc" mit den erlaubten Zeichen anlegen.
    Dann gehst Du den zu prüfenden String zeichenweise durch und prüfst ob das aktuellen Zeichen sich im String "abc" befindet.



  • Ja,

    das war mir auch die einfachste Methode. Dachte eventuell, dass ich was übersehen hätte, werde es nun so machen.

    Danke und Gruß,
    Mat.


  • Administrator

    Reguläre Ausdrücke bekommst du mit Boost:
    http://www.boost.org/
    http://www.boost.org/doc/libs/1_35_0/libs/regex/doc/html/index.html

    Die Bibliothek kann man sowieso empfehlen. Verschiedenes von Boost wird ja auch im neuen C++ Standard übernommen oder zumindest ähnlich.

    Grüssli



  • Vielleicht mit strchr? Hier ein MFC-Beispiel. Kannste dir ja umbauen.

    #define ALLOWEDCHARSINPUT "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"
    
    //s und sout sind hier CStrings...
    for(int i=0;i<s.GetLength();i++) {
      if(strchr(ALLOWEDCHARSINPUT,s[i])) {
        sout+=s[i];
      }
    }
    


  • Dravere schrieb:

    Reguläre Ausdrücke bekommst du mit Boost:
    http://www.boost.org/
    http://www.boost.org/doc/libs/1_35_0/libs/regex/doc/html/index.html

    Die Bibliothek kann man sowieso empfehlen. Verschiedenes von Boost wird ja auch im neuen C++ Standard übernommen oder zumindest ähnlich.

    Grüssli

    Boost hat wirklich interessante und nützliche Dinge. Leider bin ich im Moment daran gebunden, mit dem Standard zu arbeiten.

    Trotzdem danke, ich werde dann mal verfolgen, wann es standardisiert wird.

    _matze schrieb:

    Vielleicht mit strchr? Hier ein MFC-Beispiel. Kannste dir ja umbauen.

    #define ALLOWEDCHARSINPUT "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"
    
    //s und sout sind hier CStrings...
    for(int i=0;i<s.GetLength();i++) {
      if(strchr(ALLOWEDCHARSINPUT,s[i])) {
        sout+=s[i];
      }
    }
    

    Das entspricht der ersten Antwort, oder? Will man sich auf strings festlegen, analog dann mit s.find()...

    Gruß,
    Mat.



  • Matrim schrieb:

    Dravere schrieb:

    Reguläre Ausdrücke bekommst du mit Boost:
    http://www.boost.org/
    http://www.boost.org/doc/libs/1_35_0/libs/regex/doc/html/index.html

    Die Bibliothek kann man sowieso empfehlen. Verschiedenes von Boost wird ja auch im neuen C++ Standard übernommen oder zumindest ähnlich.

    Grüssli

    Boost hat wirklich interessante und nützliche Dinge. Leider bin ich im Moment daran gebunden, mit dem Standard zu arbeiten.

    Trotzdem danke, ich werde dann mal verfolgen, wann es standardisiert wird.

    Die Regex aus Boost sind Teil des TR1, also vom C++ Standard Comitee abgesegnet ( siehe z. B. http://en.wikipedia.org/wiki/Technical_Report_1 ). Ob dir das hilft (weil das "darf nur Standard benutzen" vom Chef kommt, den man so ueberzeugt) oder nicht (weils vom Prof kommt, der will dass du es als Uebung anders implementierst) musst du selbst entscheiden.



  • Warum nicht s.find_first_not_of( "abc")?

    Sollte es doch tun, wenn der Anwendungsfall so einfach ist wie er klingt.


  • Administrator

    Als Alternative könntest du auch std::find_if verwenden.
    http://www.cplusplus.com/reference/algorithm/find_if.html

    Beispiel:

    #include <string>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    
    template<typename T>
    struct SFindInvalid
    {
    private:
      std::vector<T> m_TVector;
    
    public:
      template<typename TIter>
      SFindInvalid(TIter First, TIter Last)
        : m_TVector(First, Last)
      { }
    
      bool operator ()(T Value)
      { return std::find(m_TVector.begin(), m_TVector.end(), Value) == m_TVector.end(); }
    };
    
    int main()
    {
      std::string AllowedChars = "abcdefg";
    
      std::string CheckString = "hello world";
    
      std::string::iterator Iter = std::find_if(CheckString.begin(), CheckString.end(),
                                                SFindInvalid<char>(AllowedChars.begin(), AllowedChars.end()));
    
      if(Iter != CheckString.end())
      { std::cout << "not allowed!" << std::endl; }
      else
      { std::cout << "allowed!" << std::endl; }
    
      return 0;
    }
    

    Könnte man sicher noch optimieren, aber so als Idee 😉

    Grüssli



  • Matrim schrieb:

    Das entspricht der ersten Antwort, oder? Will man sich auf strings festlegen, analog dann mit s.find()...

    Gruß,
    Mat.

    Ja, richtig. Ich war nur ein bisschen spät... 😉



  • Dravere schrieb:

    Könnte man sicher noch optimieren

    Was hältst du von checkString.find_first_not_of( allowedChars) != string::npos?


  • Administrator

    7H3 N4C3R schrieb:

    Dravere schrieb:

    Könnte man sicher noch optimieren

    Was hältst du von checkString.find_first_not_of( allowedChars) != string::npos?

    LoL, ja, das geht natürlich auch. Allerdings lässt sich dies nicht optimieren :p
    Bei meinem könnte man noch voraussetzen, dass die Erlaubten Charackter geordnet sind und dann ein binary_search darauf anwenden 😉
    Zudem kannst du bei meinem nicht nur nach char oder wchar_t suchen, sondern auch x beliebiges.
    Aber naja, für den Fall hier, wird die Lösung find_first_not_of wohl ausreichen, hab ich übersehen 🙂

    Grüssli



  • 7H3 N4C3R schrieb:

    Dravere schrieb:

    Könnte man sicher noch optimieren

    Was hältst du von checkString.find_first_not_of( allowedChars) != string::npos?

    War auch mein erster Gedanke 🙂



  • @Dravere:

    basic_string ist ebenfalls ein Template, das Argument mit jedem beliebigem Typ zieht also nicht. 😉 Außerdem wird die find_first_not_of Lösung sicherlich auch korrekt die char_traits zum Vergleichen benutzen. Das müsstest du noch nachziehen. 🙂

    Zusätzlich hat der Bibliothekshersteller jede Freiheit, seine find_first_not_of und jede andere Implementierung beliebig zu implementieren. Also ich bezweifele, dass das all zu unperformant ist, auch wenn man es von außen nicht optimieren kann. Außerdem, um Scott Meyers zu zitieren, "prefer library calls and algorithms over handwritten loops". 🙂


  • Administrator

    7H3 N4C3R schrieb:

    basic_string ist ebenfalls ein Template, das Argument mit jedem beliebigem Typ zieht also nicht. 😉

    Naja, da hast du zwar recht, aber für jeden beliebigen Typ noch ein char_traits zu implementieren, nervt schon etwas, nicht?
    Zudem ist basic_string nicht einfach für beliebige Typen gemacht, es geht schon eher um Strings. Bei meiner Lösung brauchst du nur Iteratoren und intern verwende ich einzig einen std::vector, welcher aber genau dafür gemacht wurde, dass er alles aufnehmen kann.

    7H3 N4C3R schrieb:

    Außerdem wird die find_first_not_of Lösung sicherlich auch korrekt die char_traits zum Vergleichen benutzen. Das müsstest du noch nachziehen. 🙂

    Nicht wirklich. Wenn ich mich recht erinnere, so ist das eq in char_traits für einen normalen String (wstring, string) gleich dem Operator == für ein wchar_t oder char. Es würde auch schwer anders gehen, nicht?

    7H3 N4C3R schrieb:

    Zusätzlich hat der Bibliothekshersteller jede Freiheit, seine find_first_not_of und jede andere Implementierung beliebig zu implementieren.

    Dabei veränderst du aber eine allgemeingültige Funktion. Es steht nirgends im Standard, dass der Parameter von find_first_not_of sortiert übergeben werden muss. Dadurch änderst du etwas an der Standardimplementierung. Das halte ich nicht für sehr sinnvoll 😉

    7H3 N4C3R schrieb:

    Also ich bezweifele, dass das all zu unperformant ist, auch wenn man es von außen nicht optimieren kann. Außerdem, um Scott Meyers zu zitieren, "prefer library calls and algorithms over handwritten loops". 🙂

    *schaut sich seine Lösung an*
    Ich habe doch kein einziger selbstgeschriebener Loop!
    Und die Optimierungen, welche man hier machen könnte, sind extrem minim, vor allem, wenn man bei Strings bleibt.
    Wenn man aber wirklich grössere Objekte hat, welche etwas länger benötigen für einen Vergleich und wenn man ein paar hundert, vielleicht gar tausend gültiger Zustände hat, dann wäre ein binary_search etwas sehr praktisches 😉

    Und ich möchte nochmals betonen:
    Für die Lösung, welche der OP sucht, ist find_first_not_of immer noch das Beste 😉

    Grüssli


Anmelden zum Antworten