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!

-
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?