Custom sscanf()



  • Hi!
    Ich möchte euch meine eigene sscanf funktion präsentieren.

    [cpp]
    #include <cstdarg>
    
    using namespace std;
    
    class StringParser
    {
      private:
        // Extended ASCII
        bool m_abCharTable[255];
    
        const char* Source;
        const char* Parsing;
    
        // Auxiliary values
        int m_nParsingIndex;
        int m_nWidth;
        bool m_bIgnore;
    
        enum
        {
            // Types, including modified types  //-> Values, must be different from each other
            T_NONE            = 0,              //
            T_BOOL            = 'b',            // -> 98
            T_CHAR            = 'c',            // -> 99
            T_STRING          = 'z',            // -> 122
            T_SHORT           = 's',            // -> 115
            T_UNSIGNED_SHORT  = 'u' + 's',      // -> 232
            T_INT             = 'i',            // -> 105
            T_UNSIGNED_INT    = 'u' + 'i',      // -> 222
            T_HEX             = 'x',            // -> 120
            T_OCT             = 'o',            // -> 111
            T_LONG            = 'l',            // -> 108
            T_UNSIGNED_LONG   = 'u' + 'l',      // -> 225
            T_FLOAT           = 'f',            // -> 102
            T_DOUBLE          = 'd',            // -> 100
    
            // Modifier
            M_UNSIGNED        = 'u',            // -> 117
        };
    
        void init()
        {
            // dont parse control codes like TAB, BELL, \n usw. (0-32)
            // dont parse ' ' (33)
            for(int i=0; i<255; i++)
            {
            	if(i<33)
            	{
                    m_abCharTable[i] = 0;
            	}
            	else
            	{
            	    m_abCharTable[i] = 1;
            	}
            }
        }
    
        void set(int c, bool b)
        {
            m_abCharTable[c] = b;
        }
    
        void set(int c1, int c2, bool b)
        {
            for(int i=c1; i<=c2; i++)
            {
                m_abCharTable[i] = b;
            }
        }
    
        int ParseOption()         // returning the Type - function can be use repetive
        {
            int n = Parsing[m_nParsingIndex];
            m_nParsingIndex++;
    
            switch(n)
            {
                case '*':
                {
                    m_bIgnore = 1;
                    return ParseOption();           // no Type yet - run again and get Type
                }
    
                case '[':
                {
                    int last;
                    bool bset = 1;
                    bool quit = 0;
    
                    while(quit == 0)
                    {
                        n = Parsing[m_nParsingIndex];
                        m_nParsingIndex++;
    
                        switch(n)
                        {
                            case ']':
                            {
                                quit = 1;
                                break;
                            }
    
                            case '^':
                            {
                                bset = 0;
                                break;
                            }
    
                            case '-':
                            {
                                if(Parsing[m_nParsingIndex] != '-')
                                {
                                    n = Parsing[m_nParsingIndex];
                                    m_nParsingIndex++;
    
                                    set(last, n, bset);
                                }
    
                                break;
                            }
    
                            default:
                            {
                                if(Parsing[m_nParsingIndex] != '-')
                                {
                                    set(n, bset);
                                    bset = 1;
                                }
    
                                last = n;
                            }
                        }
                    }
    
                    return ParseOption();            // this was no Type - 'just an option - run again
                }
    
                // Put your modifiers here
                // Take this as an example:
                case M_UNSIGNED:
                {
                    m_nParsingIndex--;
                    return n + ParseOption();       // this is a modifier - run again and get Type
                }
    
                case ' ': return T_NONE;            // there is no Type
    
                case '%': return ParseOption();
    
                default:
                {
                    if(cisdigit(n) == 1)            // there is a width
                    {
                        m_nParsingIndex--;
                        m_nWidth = catoi(Parsing, &m_nParsingIndex);
    
                        return ParseOption();       // no Type yet - run again and get Type
                    }
                    else
                    {
                        return n;                   // no Width, no Modifier - so this must be a Type
                    }
                }
            }
        }
    
      public:
        StringParser()
        {
            init();             // intialize m_abCharTable;
        }
    
        StringParser& parse(const char* Source, const char* Parsing, ...)
        {
            this->Source = Source;
            this->Parsing = Parsing;
    
            unsigned int sourcelen = cszlen(Source);
            unsigned int parsinglen = cszlen(Parsing);
    
            int nType = T_NONE;         // there is no need to make this a member
            m_bIgnore = 0;
            m_nWidth = 1;
    
            va_list pargs;              // Pointer To List of Arguments
            va_start(pargs, Parsing);   // Requires the last fixed parameter (to get the address)
    
            m_nParsingIndex = 0;
    
            for(int i=0; i<sourcelen; i++)
            {
                int s = Source[i];
                int p;
    
                if(m_nParsingIndex < parsinglen && p != '%')
                {
                    p = Parsing[m_nParsingIndex];
                    m_nParsingIndex++;
                }
    
                if(p == '%' && Parsing[m_nParsingIndex+1] != '%')
                {
                    nType = ParseOption();           // sets ignores, terminates, width, type
    
                    p = Parsing[m_nParsingIndex];
                    m_nParsingIndex++;
                }
    
                if(Source[i] == p){continue;}
    
                if(m_abCharTable[Source[i]] == 0){break;}
    
                for(int j=0; j<m_nWidth; j++)
                {
                    if(m_abCharTable[Source[i]] == 0){return *this;}
    
                    switch(nType)
                    {
                        case T_BOOL:
                        {
                            if(m_bIgnore == 0){*va_arg(pargs, bool*) = (bool)Source[i];}
                            i++;
                            break;
                        }
    
                        case T_CHAR:
                        {
                            if(m_bIgnore == 0)
                            {
                                if(m_nWidth > 1)
                                {
                                    char* c = va_arg(pargs, char*);
    
                                    for(int k=0; k<m_nWidth; k++)
                                    {
                                        if(m_abCharTable[Source[i]] == 0){*c = '\0'; return *this;}
    
                                        *c = Source[i];
                                        c++;
                                        i++;
                                    }
    
                                    *c = '\0';
                                }
                                else
                                {
                                    *va_arg(pargs, char*) = Source[i];
                                    i++;
                                }
                            }
                            else
                            {
                                for(int k=0; k<m_nWidth; k++)
                                {
                                    if(m_abCharTable[Source[i]] == 0){return *this;}
                                    i++;
                                }
                            }
    
                            break;
                        }
    
                        case T_STRING:
                        {
                            if(m_bIgnore == 0)
                            {
                                char* z = va_arg(pargs, char*);
    
                                while(m_abCharTable[Source[i]] == 1)
                                {
                                    *z = Source[i];
                                    z++;
                                    i++;
                                }
                            }
                            else
                            {
                                while(m_abCharTable[Source[i]] == 1)
                                {
                                    i++;
                                }
                            }
    
                            break;
                        }
    
                        case T_SHORT:
                        {
                            if(m_bIgnore == 0)
                            {
                                short* ptr;
                                ptr = va_arg(pargs, short*);
                                *ptr = catoi(Source, &i);
                            }
                            else
                            {
                                catoi(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_UNSIGNED_SHORT:
                        {
                            if(m_bIgnore == 0)
                            {
                                unsigned short* ptr;
                                ptr = va_arg(pargs, unsigned short*);
                                *ptr = catoi(Source, &i);
                            }
                            else
                            {
                                catoi(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_INT:
                        {
                            if(m_bIgnore == 0)
                            {
                                int* ptr;
                                ptr = va_arg(pargs, int*);
                                *ptr = catoi(Source, &i);
                            }
                            else
                            {
                                catoi(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_UNSIGNED_INT:
                        {
                            if(m_bIgnore == 0)
                            {
                                unsigned int* ptr;
                                ptr = va_arg(pargs, unsigned int*);
                                *ptr = catoi(Source, &i);
                            }
                            else
                            {
                                catoi(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_OCT:
                        {
                            if(m_bIgnore == 0)
                            {
                                int* ptr;
                                ptr = va_arg(pargs, int*);
                                *ptr = catoOct(Source, &i);
                            }
                            else
                            {
                                catoOct(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_HEX:
                        {
                            if(m_bIgnore == 0)
                            {
                                int* ptr;
                                ptr = va_arg(pargs, int*);
                                *ptr = catoHex(Source, &i);
                            }
                            else
                            {
                                catoHex(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_LONG:
                        {
                            if(m_bIgnore == 0)
                            {
                                long* ptr;
                                ptr = va_arg(pargs, long*);
                                *ptr = catol(Source, &i);
                            }
                            else
                            {
                                catol(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_UNSIGNED_LONG:
                        {
                            if(m_bIgnore == 0)
                            {
                                unsigned long* ptr;
                                ptr = va_arg(pargs, unsigned long*);
                                *ptr = catol(Source, &i);
                            }
                            else
                            {
                                catol(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_FLOAT:
                        {
                            if(m_bIgnore == 0)
                            {
                                float* ptr;
                                ptr = va_arg(pargs, float*);
                                *ptr = catof(Source, &i);
                            }
                            else
                            {
                                catof(Source, &i);
                            }
    
                            break;
                        }
    
                        case T_DOUBLE:
                        {
                            if(m_bIgnore == 0)
                            {
                                double* ptr;
                                ptr = va_arg(pargs, double*);
                                *ptr = catod(Source, &i);
                            }
                            else
                            {
                                catod(Source, &i);
                            }
    
                            break;
                        }
    
                        default: break;
                    }
                }
    
                nType = T_NONE;
                m_bIgnore = 0;
                m_nWidth = 1;
            }
    
            va_end(pargs);
    
            return *this;
        }
    
        // checks if char terminates the function when parsed
        bool is_parsed(char c)
        {
            return m_abCharTable[c];
        }
    
        // checks if char is a digit
        // IT DOESNT TAKE +/-/./, AS A DIGIT!
        bool cisdigit(const char c)
        {
            return c<'0' || c>'9' ? 0 : 1;
        }
    
        // get octadecimal integer from string
        // e.g. "12", "o12", "0o12"
        int catoOct(const char* sz, int* pos)
        {
            char digits[] = {"01234567"};
    
            int integer = 0;
    
            bool leading = 1;
    
            while(sz[*pos] != '\0')
            {
                if(sz[*pos] == 'o'){*pos += 1; leading = 0;}
    
                for(int i=0; i<8; i++)
                {
                    if(sz[*pos] == digits[i])
                    {
                        if(sz[*pos] == '0' && leading){*pos += 1; break;}
    
                        integer *= 8;
                        integer += i;
                        *pos += 1;
    
                        if(leading){leading = 0;}
    
                        break;
                    }
    
                    if(i==9){return integer;}
                }
            }
    
            return integer;
        }
    
        // get hexadecimal integer from string
        // e.g. "45AD", "0xFFFF"
        int catoHex(const char* sz, int* pos)
        {
            char digits[] = {"0123456789ABCDEF"};
    
            int integer = 0;
    
            bool leading = 1;
    
            while(sz[*pos] != '\0')
            {
                if(sz[*pos] == 'x'){*pos += 1; leading = 0;}
    
                for(int i=0; i<16; i++)
                {
                    if(sz[*pos] == digits[i])
                    {
                        if(sz[*pos] == '0' && leading){*pos += 1; break;}
    
                        integer *= 16;
                        integer += i;
                        *pos += 1;
    
                        if(leading){leading = 0;}
    
                        break;
                    }
    
                    if(i==9){return integer;}
                }
            }
    
            return integer;
        }
    
        // get short/int/long from string
        // e.g. "123", "-123", "+1", "00123"
        int catoi(const char* sz, int* pos)
        {
            char digits[] = {"0123456789"};
    
            int integer = 0;
    
            int sign = 1;
            bool leading = 1;
    
            while(sz[*pos] != '\0')
            {
                if(sz[*pos] == '-'){sign = -1; *pos += 1;}
                if(sz[*pos] == '+'){*pos += 1;}
    
                for(int i=0; i<10; i++)
                {
                    if(sz[*pos] == digits[i])
                    {
                        if(sz[*pos] == '0' && leading){*pos += 1; break;}
    
                        integer *= 10;
                        integer += i;
                        *pos += 1;
    
                        if(leading){leading = 0;}
    
                        break;
                    }
    
                    if(i==9){return integer * sign;}
                }
            }
    
            return integer * sign;;
        }
    
        long catol(const char* sz, int* pos)
        {
            char digits[] = {"0123456789"};
    
            long integer = 0;
    
            long sign = 1;
            bool leading = 1;
    
            while(sz[*pos] != '\0')
            {
                if(sz[*pos] == '-'){sign = -1; *pos += 1;}
                if(sz[*pos] == '+'){*pos += 1;}
    
                for(int i=0; i<10; i++)
                {
                    if(sz[*pos] == digits[i])
                    {
                        if(sz[*pos] == '0' && leading){*pos += 1; break;}
    
                        integer *= 10;
                        integer += i;
                        *pos += 1;
    
                        if(leading){leading = 0;}
    
                        break;
                    }
    
                    if(i==9){return integer * sign;}
                }
            }
    
            return integer * sign;;
        }
    
        // get float/double from string
        // e.g. "12.34", "123,4", "12.34e2", "+1.2", "-12.0", "0012.3"
        float catof(const char* sz, int* pos)
        {
            char digits[] = {"0123456789"};
    
            float front = 0;
            float back = 0;
            float exp = 1;
    
            float back_exp = 1;
    
            float sign = 1;
            int point = 0;      // 0...front, 1...back, 2...exp
            bool leading = 1;
    
            while(sz[*pos] != '\0')
            {
                if(sz[*pos] == '-'){sign = -1; *pos += 1;}
                if(sz[*pos] == '+'){*pos += 1;}
                if(sz[*pos] == '.' ||sz[*pos] == ','){point = 1; *pos += 1; leading = 0;}
                if(sz[*pos] == 'e' || sz[*pos] == 'E'){point = 2; *pos += 1;}
    
                for(int i=0; i<10; i++)
                {
                    if(sz[*pos] == digits[i])
                    {
                        if(sz[*pos] == '0' && leading){*pos += 1; break;}
    
                        if(point == 0){front*=10; front+=i;}
    
                        if(point == 1){back_exp*=0.1f; back*=10; back+=i;}
    
                        if(point == 2){exp = pow(10, i); }
    
                        *pos += 1;
    
                        if(leading){leading = 0;}
    
                        break;
                    }
    
                    if(i==9)
                    {
                        return (front+back*back_exp)*sign*exp;
                    }
                }
            }
    
            return (front+back*back_exp)*sign*exp;
        }
    
        double catod(const char* sz, int* pos)
        {
            char digits[] = {"0123456789"};
    
            double front = 0;
            double back = 0;
            double exp = 1;
    
            double back_exp = 1;
    
            float sign = 1;
            int point = 0;      // 0...front, 1...back, 2...exp
            bool leading = 1;
    
            while(sz[*pos] != '\0')
            {
                if(sz[*pos] == '-'){sign = -1; *pos += 1;}
                if(sz[*pos] == '+'){*pos += 1;}
                if(sz[*pos] == '.' ||sz[*pos] == ','){point = 1; *pos += 1; leading = 0;}
                if(sz[*pos] == 'e' || sz[*pos] == 'E'){point = 2; *pos += 1;}
    
                for(int i=0; i<10; i++)
                {
                    if(sz[*pos] == digits[i])
                    {
                        if(sz[*pos] == '0' && leading){*pos += 1; break;}
    
                        if(point == 0){front*=10; front+=i;}
    
                        if(point == 1){back_exp*=0.1f; back*=10; back+=i;}
    
                        if(point == 2){exp = pow(10, i); }
    
                        *pos += 1;
    
                        if(leading){leading = 0;}
    
                        break;
                    }
    
                    if(i==9)
                    {
                        return (front+back*back_exp)*sign*exp;
                    }
                }
            }
    
            return (front+back*back_exp)*sign*exp;
        }
    
        // get length of a zero-terminated string
        unsigned int cszlen(const char* sz)
        {
            unsigned int n = 0;
    
            while(*sz)
            {
                if(*sz++ == '\0'){break;}
                n++;
            }
    
            return n;
        }
    
        // isnt used in parse() but maybe I need it in future
        template<class T>
        int numbofdigits(T n)
        {
            int digits = 0;
            int step = 1;
    
            if(n<0){n = -n;}
    
            while(step <= n)
            {
                digits++;
                step *= 10;
            }
            return digits ? digits : 1;
        }
    };
    
    int main()
    {
        StringParser P;
    
        char sz[200];
    
        //"%d" -> double
        //"%o" -> octadecimal integer
        //"%x" -> hexadecimal integer
        //"%i" -> integer
        //"%l" -> long
        //"%s" -> short
        //"%ui, %ul, %us" -> unsigned int, -long, -short
        //"%z" -> string - not zero-terminated
        //"%4c" -> string with 4 char + '\0'
    
        P.parse("Das NAME ein Test bool = 1 !\n",
                "Das %z ein Test bool = %*b !\n", sz);
    
        cout<<sz<<endl;
    
        system("PAUSE");
        return 0;
    }
    [/cpp]
    

    Die Funktion kann zurzeit das selbe wie sscanf, später möchte ich sie noch ausbauen (error-handling, mehr datatypes, etc).

    Um Kommentare wird gebeten! 🙂


  • Mod

    Polygon schrieb:

    Um Kommentare wird gebeten! 🙂

    tl;dr



  • SeppJ schrieb:

    Polygon schrieb:

    Um Kommentare wird gebeten! 🙂

    tl;dr

    👍

    aber:
    //"%z" -> string - not zero-terminated
    hm? wie soll das gehen?


Anmelden zum Antworten