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.


Log in to reply