String escapen
-
Guten Abend,
ich bastle gerade eine kleine (aber feine) eigene Scriptsprache. Dafür muss ich natürlich auch Escape-Sequenzen einführen, wenn ich nicht gerade ein Feature wie Raw-Strings einbaue. Ich brauche eine Funktion escape_string, die die Escape-Sequenzen \, \', \", \t, \r und \n durch die jeweiligen Zeichen ersetzt. Wie man das mit std::string effizient hinbekommt weiß ich nicht, daher bitte ich um Hilfe.
Grüßle,
PI
-
Sag mal baut eigentlich jeder zweite hier gerade eine Scriptsprache? Vielleicht sollte man mal eine Gruppe bilden.
Wie auch immer, ich bin gerade zwar etwas inaktiv, nachdem mir keine Lösung eingefallen ist Klammern vollständig iterativ zu lösen, aber das mit den Escape-Zeichen habe ich einfach so gemacht:inline TT::Type readString() { if (*m_script == '"') { ++m_script; Range::iterator begin = m_script.pos(); while (++script) { // get max size for string if (*script == '"') break; if (*script == '\\') ++script; } m_string.resize(script.pos() - begin); std::string::iterator p = m_string.begin(); for (; begin != script.pos(); ++begin) { // parse escape characters if (*begin != '\\') { *p++ = *begin; } else { switch (*(++begin)) { // an \ can not be the last sign, see above! case '\'': *p++ = '\''; break; case '\"': *p++ = '\"'; break; case '\\': *p++ = '\\'; break; case '0': *p++ = '\0'; break; case 'a': *p++ = '\a'; break; case 'b': *p++ = '\b'; break; case 'f': *p++ = '\f'; break; case 'n': *p++ = '\n'; break; case 'r': *p++ = '\r'; break; case 't': *p++ = '\t'; break; case 'v': *p++ = '\v'; break; // Todo: insert byte escapes default: *p++ = *begin; // <------------------------- break; } } } ++script; // skip ending " m_string.resize(p - m_string.begin()); return readOperator(script, TT::const_string); } postSyntaxError("Unexpected end of file."); return TT::unkown; }
Man hat so nur eine Speicheranforderung und eine unglaubliche Performancesteigerung gegenüber operator+=. Du musst vermutlich alles etwas ändern, zumal ich hier mit meiner Range Klasse arbeite, aber im Endeffekt sollte sich das alles gut zu std::string::const_iterator's verarbeiten lassen. (Die Dereferenzierung der Range-Klasse ist immer gültig, hier solltest du mit "rohen" Iteratoren aufpassen, oder du bastelst dir eine ähnliche Klasse!)
-
cooky451 schrieb:
Sag mal baut eigentlich jeder zweite hier gerade eine Scriptsprache?
Dann bin ich wohl jeder erste, wenn ich eine Compilersprache baue. :p
#include <limits> #include <string> #include <algorithm> inline size_t char_idx(val) {return static_cast<size_t>(val) - std::numeric_limits<char>::min();} std::array<unsigned, (1 << (8*sizeof(char)))> GetLookupArray() { std::array<unsigned, (1 << (8*sizeof(char)))> ret({0}); #define FILL(value) lookup_array[char_idx('##value##')] = '\##value##'; FILL(0) FILL(a) FILL(b) FILL(f) FILL(n) FILL(r) FILL(t) FILL(v) #undef FILL ret[char_idx('\\')] = '\\'; ret[char_idx('"')] = '"'; ret[char_idx('\'')] = '\''; return ret; } char EscapeToChar(char in) { static std::array<unsigned char, (1 << (8*sizeof(char)))> lookup_array = GetLookupArray(); char result = lookup_array[char_idx(in)]; if(result == 0) throw InvalidEscapeSequenceException(in); return result; } std::string UnescapeString(std::string in) { std::string result; result.reserve(in.size()); //im Normalfall ok std::string::iterator begin = in.begin(), end = in.begin(); do { end = std::find(begin, in.end(), '\\'); result.append(begin, end); if(end+1 == in.end()) throw EscapeBeforeEndException(); else if(end != in.end()) result += EscapeToChar(*(end + 1)); begin = end + 2; } while(end < in.size()); return result; }
Ungetestet und vielleicht manche Standardfunktionen nicht ganz richtig.