Procházet zdrojové kódy

improve performance of text operations

Kolja Strohm před 6 měsíci
rodič
revize
2e9d6d994a
2 změnil soubory, kde provedl 328 přidání a 192 odebrání
  1. 287 191
      Text.cpp
  2. 41 1
      Text.h

+ 287 - 191
Text.cpp

@@ -7,6 +7,7 @@
 #ifndef WIN32
 #    include <string.h>
 #endif
+#include "Regex.h"
 
 using namespace Framework;
 
@@ -36,38 +37,58 @@ FlushingOStream::~FlushingOStream()
     onDestroy();
 }
 
+Text::Text(char* t, int l)
+    : Text()
+{
+    setTextZ(t, l); // Text setzen
+}
+
 // inhalt der Text Klasse aus Text.h
 // Konstruktor
 Text::Text()
     : ReferenceCounter(),
       txt(0),
+      length(0),
       suchGBeg(0),
       suchGEnd(0),
       precision(-1),
-      stringWriter(DynamicBuffer([this](std::stringbuf& buf) {
-          std::string str = buf.str();
-          this->append(str.c_str());
-          buf.str("");
-          return 0;
-      }))
+      stringWriter(0)
 {
     setText("");
 }
 
 Text::Text(const Text& txt)
-    : Text()
+    : ReferenceCounter(),
+      txt(0),
+      length(0),
+      suchGBeg(0),
+      suchGEnd(0),
+      precision(-1),
+      stringWriter(0)
 {
-    setText(txt);
+    setText(txt, txt.length);
 }
 
 Text::Text(const char* t)
-    : Text()
+    : ReferenceCounter(),
+      txt(0),
+      length(0),
+      suchGBeg(0),
+      suchGEnd(0),
+      precision(-1),
+      stringWriter(0)
 {
     setText(t); // Text setzen
 }
 
 Text::Text(int zahl)
-    : Text()
+    : ReferenceCounter(),
+      txt(0),
+      length(0),
+      suchGBeg(0),
+      suchGEnd(0),
+      precision(-1),
+      stringWriter(0)
 {
     *this = zahl;
 }
@@ -91,14 +112,21 @@ Text::Text(float num)
 // Destruktor
 Text::~Text()
 {
+    if (stringWriter) delete stringWriter;
     delete[] txt;
 }
 
+void Framework::Text::setTextZ(char* t, int l)
+{
+    delete[] txt; // alter Text löschen
+    length = l;
+    txt = t; // neuen Text erstellen
+}
+
 void Text::toUpperCase()
 {
     if (!txt) return;
-    int len = textLength(txt);
-    for (int i = 0; i < len; i++)
+    for (int i = 0; i < length; i++)
     {
         if (txt[i] >= 'a' && txt[i] <= 'z') txt[i] = (char)(txt[i] - 32);
         switch (txt[i])
@@ -119,8 +147,7 @@ void Text::toUpperCase()
 void Text::toLowerCase()
 {
     if (!txt) return;
-    int len = textLength(txt);
-    for (int i = 0; i < len; i++)
+    for (int i = 0; i < length; i++)
     {
         if (txt[i] >= 'A' && txt[i] <= 'Z') txt[i] = (char)(txt[i] + 32);
         switch (txt[i])
@@ -149,22 +176,23 @@ void Text::setSuchGrenzen(
 
 void Text::setText(const char* t) // ersetzt den Text
 {
-    delete[] txt;                   // alter Text löschen
-    int l = (int)textLength(t);     // Länge des neuen Textes ermitteln
-    txt = new char[(__int64)l + 1]; // neuen Text erstellen
-    for (int i = 0; i < l; ++i)     // Text befüllen
+    delete[] txt;                        // alter Text löschen
+    length = (int)textLength(t);         // Länge des neuen Textes ermitteln
+    txt = new char[(__int64)length + 1]; // neuen Text erstellen
+    for (int i = 0; i < length; ++i)     // Text befüllen
         txt[i] = t[i];
-    txt[l] = '\0'; // Textende Festlegen
+    txt[length] = '\0'; // Textende Festlegen
 }
 
 // unconstant
 void Text::setText(const char* t, int l) // ersetzt den Text
 {
-    delete[] txt;                   // alter Text löschen
-    txt = new char[(__int64)l + 1]; // neuen Text erstellen
-    for (int i = 0; i < l; ++i)     // Text befüllen
+    delete[] txt; // alter Text löschen
+    length = l;
+    txt = new char[(__int64)length + 1]; // neuen Text erstellen
+    for (int i = 0; i < length; ++i)     // Text befüllen
         txt[i] = t[i];
-    txt[l] = '\0'; // Textende Festlegen
+    txt[length] = '\0'; // Textende Festlegen
 }
 
 void Text::setText(Text* t)
@@ -180,63 +208,55 @@ void Text::append(char c) // h
 
 void Text::append(const char* t) // hängt an den Text an
 {
-    int tl = (int)textLength(t);                 // länge der übergabe
-    int txl = getLength();                       // länge des Textes
-    char* res = new char[(__int64)tl + txl + 1]; // neuen Text erstellen
-    for (int i = 0; i < txl; ++i)                // mit jetzigem Text füllen
+    int tl = (int)textLength(t);                    // länge der übergabe
+    char* res = new char[(__int64)tl + length + 1]; // neuen Text erstellen
+    for (int i = 0; i < length; ++i)                // mit jetzigem Text füllen
         res[i] = txt[i];
     for (int i = 0; i < tl; ++i) // Übergabe anhängen
-        res[txl + i] = t[i];
-    res[txl + tl] = '\0'; // Textende festlegen
-    setText(res);         // Test setzen
-    delete[] res;         // Speicher freigeben
+        res[length + i] = t[i];
+    res[length + tl] = '\0';    // Textende festlegen
+    setTextZ(res, length + tl); // Test setzen
 }
 
 void Text::appendHex(int num) // hängt die zahl in hex anden Text an
 {
-    int l = getLength();
-    char* res = new char[(__int64)l + 9];
-    for (int i = 0; i < l; ++i)
+    char* res = new char[(__int64)length + 9];
+    for (int i = 0; i < length; ++i)
         res[i] = txt[i];
     std::stringstream stream;
     stream << std::setfill('0') << std::setw((int)sizeof(int) * 2) << std::hex
            << num;
     std::string str = stream.str();
-    for (int i = l; i < l + 8; ++i)
-        res[i] = str.c_str()[i - l];
-    res[l + 8] = 0;
-    setText(res);
-    delete[] res;
+    for (int i = length; i < length + 8; ++i)
+        res[i] = str.c_str()[i - length];
+    res[length + 8] = 0;
+    setTextZ(res, length + 8);
 }
 
 void Text::appendHex(__int64 num) // hängt die zahl in hex anden Text an
 {
-    int l = getLength();
-    char* res = new char[(__int64)l + 17];
-    for (int i = 0; i < l; ++i)
+    char* res = new char[(__int64)length + 17];
+    for (int i = 0; i < length; ++i)
         res[i] = txt[i];
     std::stringstream stream;
     stream << std::setfill('0') << std::setw((int)sizeof(__int64) * 2)
            << std::hex << num;
     std::string str = stream.str();
-    for (int i = l; i < l + 16; ++i)
-        res[i] = str.c_str()[i - l];
-    res[l + 16] = 0;
-    setText(res);
-    delete[] res;
+    for (int i = length; i < length + 16; ++i)
+        res[i] = str.c_str()[i - length];
+    res[length + 16] = 0;
+    setTextZ(res, length + 16);
 }
 
-void Text::append(const char* t, int l) // hängt an den Text an
-{
-    int txl = getLength();                      // länge des Textes
-    char* res = new char[(__int64)l + txl + 1]; // neuen Text erstellen
-    for (int i = 0; i < txl; ++i)               // mit jetzigem Text füllen
+void Text::append(const char* t, int l)            // hängt an den Text an
+{                                                  // länge des Textes
+    char* res = new char[(__int64)l + length + 1]; // neuen Text erstellen
+    for (int i = 0; i < length; ++i)               // mit jetzigem Text füllen
         res[i] = txt[i];
     for (int i = 0; i < l; ++i) // Übergabe anhängen
-        res[txl + i] = t[i];
-    res[txl + l] = '\0';   // Textende festlegen
-    setText(res, txl + l); // Test setzen
-    delete[] res;          // Speicher freigeben
+        res[length + i] = t[i];
+    res[length + l] = '\0';    // Textende festlegen
+    setTextZ(res, length + l); // Test setzen
 }
 
 void Text::append(Text* t)
@@ -275,7 +295,20 @@ void Text::append(double num)
     std::stringstream ss;
     if (precision >= 0) ss.precision(precision);
     ss << std::fixed << num;
-    append(ss.str().c_str());
+    std::string string = ss.str();
+    const char* str = string.c_str();
+    int len = (int)textLength(str);
+    for (int i = len - 1; i > 0; i--)
+    {
+        if (str[i] == '0')
+            len--;
+        else
+        {
+            if (str[i] == '.') len--;
+            break;
+        }
+    }
+    append(str, len);
 }
 
 void Text::append(float num)
@@ -283,48 +316,66 @@ void Text::append(float num)
     std::stringstream ss;
     if (precision >= 0) ss.precision(precision);
     ss << std::fixed << num;
-    append(ss.str().c_str());
+    std::string string = ss.str();
+    const char* str = string.c_str();
+    int len = (int)textLength(str);
+    for (int i = len - 1; i > 0; i--)
+    {
+        if (str[i] == '0')
+            len--;
+        else
+        {
+            if (str[i] == '.') len--;
+            break;
+        }
+    }
+    append(str, len);
 }
 
 //! Gibt einen ostream zurück, der alle ausgaben an diesen Text anhängt
 FlushingOStream Text::append()
 {
-    return FlushingOStream(&stringWriter);
+    if (!stringWriter)
+    {
+        stringWriter = new DynamicBuffer([this](std::stringbuf& buf) {
+            std::string str = buf.str();
+            this->append(str.c_str());
+            buf.str("");
+            return 0;
+        });
+    }
+    return FlushingOStream(stringWriter);
 }
 
 void Text::insert(int p, char c) // Fügt an stelle p ein
 {
-    if (p > getLength() || p < 0) // Auf unsinnige übergabe prüfen
+    if (p > length || p < 0) // Auf unsinnige übergabe prüfen
         return;
-    int txl = getLength();                  // Länge des Textes
-    char* res = new char[(__int64)txl + 2]; // neuer Text erstellen
-    for (int i = 0; i < p; ++i)             // Text füllen
+    char* res = new char[(__int64)length + 2]; // neuer Text erstellen
+    for (int i = 0; i < p; ++i)                // Text füllen
         res[i] = txt[i];
     res[p] = c;
-    for (int i = p; i < txl; ++i) // Text füllen
+    for (int i = p; i < length; ++i) // Text füllen
         res[i + 1] = txt[i];
-    res[txl + 1] = '\0'; // Text ende festlegen
-    setText(res);        // Text setzen
-    delete[] res;        // Speicher freigeben
+    res[length + 1] = '\0';    // Text ende festlegen
+    setTextZ(res, length + 1); // Text setzen
 }
 
 void Text::insert(int p, const char* t) // Fügt an stelle p ein
 {
-    if (p > getLength() || p < 0
+    if (p > length || p < 0
         || textLength(t) <= 0) // Auf unsinnige übergabe prüfen
         return;
-    int tl = (int)textLength(t);                 // Länge der übergabe
-    int txl = getLength();                       // Länge des Textes
-    char* res = new char[(__int64)tl + txl + 1]; // neuer Text erstellen
-    for (int i = 0; i < p; ++i)                  // Text füllen
+    int tl = (int)textLength(t);                    // Länge der übergabe
+    char* res = new char[(__int64)tl + length + 1]; // neuer Text erstellen
+    for (int i = 0; i < p; ++i)                     // Text füllen
         res[i] = txt[i];
     for (int i = 0; i < tl; ++i) // Text einfügen
         res[i + p] = t[i];
-    for (int i = p; i < txl; ++i) // Text füllen
+    for (int i = p; i < length; ++i) // Text füllen
         res[i + tl] = txt[i];
-    res[tl + txl] = '\0'; // Text ende festlegen
-    setText(res);         // Text setzen
-    delete[] res;         // Speicher freigeben
+    res[tl + length] = '\0';    // Text ende festlegen
+    setTextZ(res, length + tl); // Text setzen
 }
 
 void Text::insert(int p, Text* t)
@@ -334,6 +385,73 @@ void Text::insert(int p, Text* t)
     t->release();                // Übergabe loslassen
 }
 
+void Framework::Text::regexReplace(
+    const char* regex, const char* replacement, Regex::RegexConfig* config)
+{
+    regexReplace(
+        regex, [replacement](Regex::Result&) { return replacement; }, config);
+}
+
+void Framework::Text::regexReplace(const char* regex,
+    std::function<Text(Regex::Result&)> replacementFunction,
+    Regex::RegexConfig* config)
+{
+    auto matcher
+        = config == 0 ? Regex::parse(regex) : Regex::parse(regex, *config);
+    if (!matcher) return;
+    auto result = matcher->match(txt, length);
+    if (result->getEintragAnzahl() > 0)
+    {
+        int replacedLength = 0;
+        int replacementLength = 0;
+        Text* replacements = new Text[result->getEintragAnzahl()];
+        int i = 0;
+#ifdef WIN32
+#    pragma warning(push)
+#    pragma warning(disable : 6385)
+#endif
+        for (Regex::Result* match : *result)
+        {
+            replacedLength += match->getEnd() - match->getStart();
+            replacements[i] = replacementFunction(*match);
+            replacementLength += replacements[i].getLength();
+            i++;
+        }
+        int newLength = length - replacedLength + replacementLength;
+        char* newText = new char[(__int64)newLength + 1];
+        int pos = 0;
+        int newPos = 0;
+        int j = 0;
+        for (Regex::Result* match : *result)
+        {
+            for (int i = 0; i < match->getStart() - pos; i++)
+            {
+                newText[newPos + i] = txt[pos + i];
+            }
+            newPos += match->getStart() - pos;
+            pos = match->getEnd();
+            for (int i = 0; i < replacements[j].getLength(); i++)
+            {
+                newText[newPos + i] = replacements[j][i];
+            }
+            newPos += replacements[j].getLength();
+            j++;
+        }
+        for (int i = pos; i < getLength(); i++)
+        {
+            newText[newPos + i - pos] = txt[i];
+        }
+#ifdef WIN32
+#    pragma warning(pop)
+#endif
+        newText[newLength] = '\0';
+        setTextZ(newText, newLength);
+        delete[] replacements;
+    }
+    result->release();
+    matcher->release();
+}
+
 void Text::ersetzen(
     int p1, int p2, const char* t) // Ersetzt den Text von p1 bis p2
 {
@@ -360,9 +478,8 @@ void Text::ersetzen(char c1, char c2) // ersetzt jedes c1 durch c2
         return;
     if (!hat(c1)) // prüfen ob c1 vorhanden
         return;
-    int l = getLength(); // Text Länge
     int suchGCount = 0;
-    for (int i = 0; i < l; ++i) // Text durchsuchen
+    for (int i = 0; i < length; ++i) // Text durchsuchen
     {
         bool b = suchGCount != 0;
         if (txt[i] == c1 && !suchGCount) txt[i] = c2; // Text ersetzen
@@ -374,23 +491,24 @@ void Text::ersetzen(char c1, char c2) // ersetzt jedes c1 durch c2
 
 void Text::ersetzen(const char* t1, const char* t2) // ersetzt jedes t1 durch t2
 {
-    int txl = getLength();         // Text Länge
     int t1l = (int)textLength(t1); // Länge der Übergaben
     int t2l = (int)textLength(t2);
-    if (t1l > txl || t1l <= 0) // Auf unsinnige übergabe prüfen
+    if (t1l > length || t1l <= 0) // Auf unsinnige übergabe prüfen
         return;
     if (!hat(t1)) // prüfen ob t1 vorhanden
         return;
     int anz = anzahlVon(t1); // Anzahl von t1 im Text
     int* begin = new int[anz];
     int* end = new int[anz];
+    int searchStart = 0;
     for (int i = 0; i < anz; ++i) // Positionen von t1 speichern
     {
-        begin[i] = positionVon(t1, i);
+        begin[i] = positionVon(searchStart, t1);
         end[i] = begin[i] + t1l;
+        searchStart = end[i];
     }
-    int resl = (txl - (anz * t1l)) + (anz * t2l) + 1; // Länge des Ergebneses
-    char* res = new char[resl];                       // neuer Text erstellen
+    int resl = (length - (anz * t1l)) + (anz * t2l) + 1; // Länge des Ergebneses
+    char* res = new char[resl];                          // neuer Text erstellen
     int rep = 0;              // Speichert bei welchen t1 man sich befindet
     int last = 0;             // Füllposition von txt
     int neu = 0;              // Füllporition von res
@@ -416,10 +534,9 @@ void Text::ersetzen(const char* t1, const char* t2) // ersetzt jedes t1 durch t2
         }
     }
     res[resl - 1] = '\0'; // Textende festlegen
-    setText(res);         // Text setzen
+    setTextZ(res, resl);  // Text setzen
     delete[] begin;       // Speicher freigeben
     delete[] end;
-    delete[] res;
 }
 
 void Text::ersetzen(Text* t1, const char* t2)
@@ -460,9 +577,8 @@ void Text::ersetzen(int index, char c1, char c2) // ersetzt das i-te c1 durch c2
 void Text::ersetzen(
     int index, const char* t1, const char* t2) // ersetzt das i-te t1 durch t2
 {
-    int txl = getLength();                   // Text Länge
-    int t1l = (int)textLength(t1);           // Länge der Übergaben
-    if (t1l >= txl || t1l <= 0 || index < 0) // Auf unsinnige übergabe prüfen
+    int t1l = (int)textLength(t1);              // Länge der Übergaben
+    if (t1l >= length || t1l <= 0 || index < 0) // Auf unsinnige übergabe prüfen
         return;
     if (!hat(t1)) // prüfen ob t1 vorhanden
         return;
@@ -504,23 +620,20 @@ void Text::fillText(
     for (int i = 0; i < len; ++i)
         res[i] = c;
     res[len] = '\0';
-    setText(res);
-    delete[] res;
+    setTextZ(res, len);
 }
 
 void Text::remove(int p) // löscht p
 {
-    int l = getLength(); // Text Länge
-    if (p < 0 || p >= l) // Auf unsinnige übergabe prüfen
+    if (p < 0 || p >= length) // Auf unsinnige übergabe prüfen
         return;
-    char* res = new char[l];             // neuen Text anlegen
-    for (int i = 0; i < p && i < l; ++i) // Text befüllen
+    char* res = new char[length];             // neuen Text anlegen
+    for (int i = 0; i < p && i < length; ++i) // Text befüllen
         res[i] = txt[i];
-    for (int i = p + 1; i < l; ++i)
+    for (int i = p + 1; i < length; ++i)
         res[i - 1] = txt[i];
-    res[l - 1] = 0;
-    setText(res); // Text setzen
-    delete[] res; // Speicher freigeben
+    res[length - 1] = 0;
+    setTextZ(res, length - 1); // Text setzen
 }
 
 void Text::remove(int p1, int p2) // löscht von p1 zu p2 ( p2 bleibt )
@@ -532,31 +645,28 @@ void Text::remove(int p1, int p2) // l
         p1 = p2;
         p2 = x;
     }
-    int l = getLength(); // Länge des Testes
-    if (p1 < 0)          // Auf unsinnige übergabe prüfen
+    if (p1 < 0) // Auf unsinnige übergabe prüfen
         p1 = 0;
-    if (p2 > l) p2 = l;
-    int resl = l - (p2 - p1);                // Länge vom Ergebnis
+    if (p2 > length) p2 = length;
+    int resl = length - (p2 - p1);           // Länge vom Ergebnis
     char* res = new char[(__int64)resl + 1]; // Neuen Text erstellen
     for (int i = 0; i < p1; ++i)             // Text füllen
         res[i] = txt[i];
-    for (int i = p2; i < l; ++i)
+    for (int i = p2; i < length; ++i)
         res[i - (p2 - p1)] = txt[i];
-    res[resl] = '\0'; // Testende festlegen
-    setText(res);     // Text setzen
-    delete[] res;     // Speicher freigeben
+    res[resl] = '\0';    // Testende festlegen
+    setTextZ(res, resl); // Text setzen
 }
 
 void Text::remove(char c) // löscht jetes c
 {
     if (!hat(c)) // prüfen ob c vorhanden
         return;
-    int l = getLength();                        // Länge des Textes
-    int anz = anzahlVon(c);                     // Anzahl von c
-    char* res = new char[(__int64)l - anz + 1]; // neuen Text erstellen
+    int anz = anzahlVon(c);                          // Anzahl von c
+    char* res = new char[(__int64)length - anz + 1]; // neuen Text erstellen
     int anz2 = 0;
     int suchGCount = 0;
-    for (int i = 0; i < l; ++i) // Text befüllen
+    for (int i = 0; i < length; ++i) // Text befüllen
     {
         bool b = suchGCount != 0;
         if (txt[i] == c && !suchGCount)
@@ -573,16 +683,14 @@ void Text::remove(char c) // l
                 res[i - anz2] = txt[i];
         }
     }
-    res[l - anz] = '\0'; // Textende festlegen
-    setText(res);        // Text setzen
-    delete[] res;        // Speicher freigeben
+    res[length - anz] = '\0';    // Textende festlegen
+    setTextZ(res, length - anz); // Text setzen
 }
 
 void Text::remove(const char* t) // löscht jetes t
 {
     int tl = (int)textLength(t); // Länge der Übergabe
-    int txl = getLength();       // Länge des Textes
-    if (tl <= 0 || tl > txl)     // Auf unsinnige übergabe prüfen
+    if (tl <= 0 || tl > length)  // Auf unsinnige übergabe prüfen
         return;
     if (!hat(t)) // prüfen ob Text ein t enthält
         return;
@@ -590,10 +698,10 @@ void Text::remove(const char* t) // l
     int* begin = new int[anz];
     for (int i = 0; i < anz; ++i) // begin aller t-s finden
         begin[i] = positionVon(t, i);
-    int resl = txl - (anz * tl);             // Länge vom Ergebnes
+    int resl = length - (anz * tl);          // Länge vom Ergebnes
     char* res = new char[(__int64)resl + 1]; // neuen Text erzeugen
     int del = 0;
-    for (int i = 0; i < txl; ++i) // Text befüllen
+    for (int i = 0; i < length; ++i) // Text befüllen
     {
         if (del < anz && i == begin[del]) // Text auslassen
         {
@@ -603,10 +711,9 @@ void Text::remove(const char* t) // l
         else
             res[i - (del * tl)] = txt[i]; // Text befüllen
     }
-    res[resl] = '\0'; // Text ende festlegen
-    setText(res);     // Text setzen
+    res[resl] = '\0';    // Text ende festlegen
+    setTextZ(res, resl); // Text setzen
     delete[] begin;
-    delete[] res; // Speicher freigeben
 }
 
 void Text::remove(Text* t)
@@ -625,16 +732,14 @@ void Text::remove(int index, char c)
         return;
     int pos = positionVon(c, index); // Position vom i-ten c
     if (pos < 0) return;
-    int l = getLength(); // Länge des Textes
-    if (!l) return;
-    char* res = new char[l];               // neuen Text erzeugen
-    for (int i = 0; i < pos && i < l; ++i) // Text befüllen
+    if (!length) return;
+    char* res = new char[length];               // neuen Text erzeugen
+    for (int i = 0; i < pos && i < length; ++i) // Text befüllen
         res[i] = txt[i];
-    for (int i = pos + 1; i < l; ++i)
+    for (int i = pos + 1; i < length; ++i)
         res[i - 1] = txt[i];
-    res[l - 1] = '\0'; // Text ende festlegen
-    setText(res);      // Text setzen
-    delete[] res;      // Speicher freigeben
+    res[length - 1] = '\0';    // Text ende festlegen
+    setTextZ(res, length - 1); // Text setzen
 }
 
 void Text::remove(int index, const char* t) // löscht das i-te t
@@ -647,16 +752,14 @@ void Text::remove(int index, const char* t) // l
         return;
     int pos = positionVon(t, index); // Position vom i-ten c
     if (pos < 0) return;
-    int l = getLength(); // Länge des Textes
-    if (!l) return;
-    char* res = new char[(__int64)l - tl + 1];      // neuen Text erzeugen
-    for (int i = 0; i < pos && i < l - tl + 1; ++i) // Text befüllen
+    if (!length) return;
+    char* res = new char[(__int64)length - tl + 1];      // neuen Text erzeugen
+    for (int i = 0; i < pos && i < length - tl + 1; ++i) // Text befüllen
         res[i] = txt[i];
-    for (int i = pos + tl; i < l; ++i)
+    for (int i = pos + tl; i < length; ++i)
         res[i - tl] = txt[i];
-    res[l - tl] = '\0'; // Text ende festlegen
-    setText(res);       // Text setzen
-    delete[] res;       // Speicher freigeben
+    res[length - tl] = '\0';    // Text ende festlegen
+    setTextZ(res, length - tl); // Text setzen
 }
 
 void Text::remove(int i, Text* t)
@@ -706,8 +809,7 @@ void Text::setPrecision(
 // constant
 int Text::getLength() const // gibt die Text länge zurück
 {
-    if (!txt) return -1;
-    return textLength(txt);
+    return length;
 }
 
 int Text::getLKick(int pos) const
@@ -749,12 +851,11 @@ int Text::getOKick(int pos) const
 
 int Text::getRKick(int pos) const
 {
-    int tl = getLength();
     if (txt[pos] == ' ')
     {
         int ret = 1;
-        for (;
-             ret + pos < tl && txt[pos + ret] == ' ' && txt[pos + ret] != '\n';
+        for (; ret + pos < length && txt[pos + ret] == ' '
+               && txt[pos + ret] != '\n';
              ++ret)
             ;
         return pos + ret;
@@ -762,8 +863,8 @@ int Text::getRKick(int pos) const
     else
     {
         int ret = 1;
-        for (;
-             ret + pos < tl && txt[pos + ret] != ' ' && txt[pos + ret] != '\n';
+        for (; ret + pos < length && txt[pos + ret] != ' '
+               && txt[pos + ret] != '\n';
              ++ret)
             ;
         return pos + ret;
@@ -772,18 +873,18 @@ int Text::getRKick(int pos) const
 
 int Text::getUKick(int pos) const
 {
-    if (!hat('\n')) return getLength();
+    if (!hat('\n')) return length;
     int lpos = 0;
     while (pos - lpos > 0 && txt[pos - lpos - 1] != '\n')
         ++lpos;
     int llen = 1;
-    while (pos + llen - 1 < getLength() && txt[pos + llen - 1] != '\n')
+    while (pos + llen - 1 < length && txt[pos + llen - 1] != '\n')
         ++llen;
     int vllen = 1;
-    while (pos + llen + vllen - 1 < getLength()
-           && txt[pos + llen + vllen - 1] != '\n')
+    while (
+        pos + llen + vllen - 1 < length && txt[pos + llen + vllen - 1] != '\n')
         ++vllen;
-    if (vllen == 1) return pos + llen < getLength() ? pos + llen : getLength();
+    if (vllen == 1) return pos + llen < length ? pos + llen : length;
     if (vllen < lpos) return pos + llen + vllen - 1;
     return pos + llen + lpos;
 }
@@ -798,13 +899,18 @@ bool Text::hat(Text* t) const // enth
 }
 
 bool Text::hat(const char* t) const
+{
+    return hat(0, t);
+}
+
+bool Framework::Text::hat(int searchStartIndex, const char* t) const
 {
     int tl = (int)textLength(t); // Länge der Übergabe
-    int txl = getLength();       // Länge des Textes
-    if (tl <= 0 || tl > txl)     // Auf unsinnige übergabe prüfen
+    if (tl <= 0
+        || tl > length - searchStartIndex) // Auf unsinnige übergabe prüfen
         return 0;
     int suchGCount = 0;
-    for (int i = 0; i + tl <= txl; ++i) // Text durchsuchen
+    for (int i = searchStartIndex; i + tl <= length; ++i) // Text durchsuchen
     {
         if (!suchGCount)
         {
@@ -845,9 +951,8 @@ bool Text::hatAt(int pos, Text* t) const
 //  pos: die position an der die zeichenkette im string beginnen soll
 bool Text::hatAt(int pos, const char* t) const
 {
-    int tl = (int)textLength(t);   // Länge der Übergabe
-    int txl = getLength();         // Länge des Textes
-    if (tl <= 0 || tl + pos > txl) // Auf unsinnige übergabe prüfen
+    int tl = (int)textLength(t);      // Länge der Übergabe
+    if (tl <= 0 || tl + pos > length) // Auf unsinnige übergabe prüfen
         return 0;
     bool b = 1;
     for (int i = 0; i < tl; ++i) // Text überprüfen
@@ -857,10 +962,9 @@ bool Text::hatAt(int pos, const char* t) const
 
 bool Text::hat(char c) const // enthält c
 {
-    int l = getLength(); // Text Länge
     bool ret = 0;
     int suchGCount = 0;
-    for (int i = 0; i < l; ++i) // suchen
+    for (int i = 0; i < length; ++i) // suchen
     {
         bool b = suchGCount != 0;
         if (!suchGCount) // überprüfen
@@ -875,11 +979,10 @@ bool Text::hat(char c) const // enth
 
 bool Text::istGleich(const char* t) const // prüft ob det Text gleich t ist
 {
-    int txl = getLength();       // Text Länge
     int tl = (int)textLength(t); // Länge der Übergabe
-    if (txl != tl)               // Auf unsinniege Übergabe prüfen
+    if (length != tl)            // Auf unsinniege Übergabe prüfen
         return 0;
-    if (txl == -1) return 1;
+    if (length == -1) return 1;
     bool ret = true;
     for (int i = 0; i < tl; ++i) // prüfen
         ret &= txt[i] == t[i];
@@ -901,9 +1004,8 @@ const char* Text::getText() const // gibt Text zur
 int Text::anzahlVon(char c) const // gibt die Anzahl von c im Text zurück
 {
     int ret = 0;
-    int l = getLength(); // Text Länge
     int suchGCount = 0;
-    for (int i = 0; i < l; ++i) // suchen
+    for (int i = 0; i < length; ++i) // suchen
     {
         bool b = suchGCount != 0;
         ret += txt[i] == c && !suchGCount; // zählen
@@ -917,12 +1019,11 @@ int Text::anzahlVon(char c) const // gibt die Anzahl von c im Text zur
 int Text::anzahlVon(const char* t) const // gibt die Anzahl von t im Text zurück
 {
     int tl = (int)textLength(t); // Länge der Übergabe
-    int txl = getLength();       // Länge des Textes
-    if (tl <= 0 || tl > txl)     // Auf unsinnige übergabe prüfen
+    if (tl <= 0 || tl > length)  // Auf unsinnige übergabe prüfen
         return 0;
     int ret = 0;
     int suchGCount = 0;
-    for (int i = 0; i + tl <= txl; ++i) // suchen
+    for (int i = 0; i + tl <= length; ++i) // suchen
     {
         bool b = suchGCount != 0;
         if (!suchGCount)
@@ -956,9 +1057,8 @@ int Text::anzahlVon(Text* t) const
 
 int Text::positionVon(char c) const // gibt die Position des ersten c zurück
 {
-    int l = getLength(); // Text Länge
     int suchGCount = 0;
-    for (int i = 0; i < l; ++i) // suchen
+    for (int i = 0; i < length; ++i) // suchen
     {
         bool b = suchGCount != 0;
         if (txt[i] == c && !suchGCount) // überprüfen
@@ -974,12 +1074,16 @@ int Text::positionVon(char c) const // gibt die Position des ersten c zur
 int Text::positionVon(
     const char* t) const // gibt die Position des ersten t zurück
 {
-    int tl = (int)textLength(t); // Länge der Übergabe
-    int txl = getLength();       // Länge des Textes
-    if (tl <= 0 || tl > txl)     // Auf unsinnige übergabe prüfen
+    return positionVon(0, t);
+}
+
+int Framework::Text::positionVon(int searchStart, const char* t) const
+{
+    int tl = (int)textLength(t);              // Länge der Übergabe
+    if (tl <= 0 || tl > length - searchStart) // Auf unsinnige übergabe prüfen
         return -1;
     int suchGCount = 0;
-    for (int i = 0; i + tl <= txl; ++i) // suchen
+    for (int i = searchStart; i + tl <= length; ++i) // suchen
     {
         bool b = suchGCount != 0;
         if (!suchGCount)
@@ -1014,10 +1118,9 @@ int Text::positionVon(Text* t) const
 int Text::positionVon(
     char c, int index) const // gibt die Position des i-ten c zurück
 {
-    int l = getLength(); // Text Länge
     int ii = 0;
     int suchGCount = 0;
-    for (int i = 0; i < l; ++i) // suchen
+    for (int i = 0; i < length; ++i) // suchen
     {
         bool b = suchGCount != 0;
         if (txt[i] == c && !suchGCount) // überprüfen
@@ -1044,12 +1147,11 @@ int Text::positionVon(
     const char* t, int index) const // gibt die Position des i-ten t zurück
 {
     int tl = (int)textLength(t); // Länge der Übergabe
-    int txl = getLength();       // Länge des Textes
-    if (tl <= 0 || tl > txl)     // Auf unsinnige übergabe prüfen
+    if (tl <= 0 || tl > length)  // Auf unsinnige übergabe prüfen
         return 0;
     int i2 = 0;
     int suchGCount = 0;
-    for (int i = 0; i + tl <= txl; ++i) // suchen
+    for (int i = 0; i + tl <= length; ++i) // suchen
     {
         bool b = suchGCount != 0;
         if (!suchGCount)
@@ -1102,8 +1204,7 @@ Text* Text::getTeilText(
         p1 = p2;
         p2 = x;
     }
-    int l = getLength();  // Text Länge
-    if (p1 < 0 || p2 > l) // Auf unsinnige übergabe prüfen
+    if (p1 < 0 || p2 > length) // Auf unsinnige übergabe prüfen
         return new Text("");
     char* cp = new char[(__int64)p2 - p1 + 1]; // neuen Text erstellen
     for (int i = p1; i < p2; ++i)              // Text befüllen
@@ -1111,9 +1212,7 @@ Text* Text::getTeilText(
         cp[i - p1] = txt[i];
     }
     cp[p2 - p1] = '\0';
-    Text* t = new Text(cp); // Text zurückgeben
-    delete[] cp;
-    return t;
+    return new Text(cp, p2 - p1); // Text zurückgeben
 }
 
 Text* Text::getTeilText(int p) const // gibt den Text von p bis zum Ende zurück
@@ -1125,9 +1224,8 @@ Text* Text::getTeilText(int p) const // gibt den Text von p bis zum Ende zur
 int Text::hashCode() const
 {
     int result = 0;
-    int len = getLength();
-    for (int i = 0; i < len; i++)
-        result += (int)pow(txt[i] * 31, len - 1 - i);
+    for (int i = 0; i < length; i++)
+        result += (int)pow(txt[i] * 31, length - 1 - i);
     return result;
 }
 
@@ -1209,14 +1307,14 @@ Text::operator const char*() const
 
 Text::operator int() const
 {
-    if (getLength() > 2 && txt[0] == '0' && txt[1] == 'x')
+    if (length > 2 && txt[0] == '0' && txt[1] == 'x')
         return TextZuInt((txt + 2), 16);
     return TextZuInt(txt, 10);
 }
 
 Text::operator __int64() const
 {
-    if (getLength() > 2 && txt[0] == '0' && txt[1] == 'x')
+    if (length > 2 && txt[0] == '0' && txt[1] == 'x')
         return TextZuInt64((txt + 2), 16);
     return TextZuInt64(txt, 10);
 }
@@ -1233,29 +1331,27 @@ Text::operator float() const
 
 bool Text::operator>(Text& t) const
 {
-    int len1 = getLength();
     int len2 = t.getLength();
     const char* txt2 = t;
-    for (int i = 0; i < len1 && i < len2; ++i)
+    for (int i = 0; i < length && i < len2; ++i)
     {
         if (txt[i] > txt2[i]) return 1;
         if (txt[i] < txt2[i]) return 0;
     }
-    if (len1 > len2) return 1;
+    if (length > len2) return 1;
     return 0;
 }
 
 bool Text::operator<(Text& t) const
 {
-    int len1 = getLength();
     int len2 = t.getLength();
     const char* txt2 = t;
-    for (int i = 0; i < len1 && i < len2; ++i)
+    for (int i = 0; i < length && i < len2; ++i)
     {
         if (txt[i] < txt2[i]) return 1;
         if (txt[i] > txt2[i]) return 0;
     }
-    if (len1 < len2) return 1;
+    if (length < len2) return 1;
     return 0;
 }
 

+ 41 - 1
Text.h

@@ -11,6 +11,12 @@ namespace Framework
 {
     class Text; //! aus dieser Datei
 
+    namespace Regex
+    {
+        class Result;
+        class RegexConfig;
+    } // namespace Regex
+
     class DynamicBuffer : public std::stringbuf
     {
     private:
@@ -40,10 +46,13 @@ namespace Framework
     {
     private:
         char* txt;
+        int length;
         char suchGBeg;
         char suchGEnd;
         int precision;
-        DynamicBuffer stringWriter;
+        DynamicBuffer* stringWriter;
+
+        DLLEXPORT Text(char* txt, int l);
 
     public:
         //! Erstellt ein neues Text Objekt mit dem Wert ""
@@ -65,6 +74,11 @@ namespace Framework
         DLLEXPORT Text(float num);
         //! Löscht den Text
         DLLEXPORT ~Text();
+
+    private:
+        DLLEXPORT void setTextZ(char* t, int l);
+
+    public:
         //! Wandelt alle buchstaben in großbuchstaben um
         DLLEXPORT void toUpperCase();
         //! Wandelt alle buchstaben in kleinbuchstaben um
@@ -142,6 +156,22 @@ namespace Framework
         //! eingefügt werden soll \param t Der Text, dessen Kopie an der Stelle
         //! eingefügt werden soll
         DLLEXPORT void insert(int p, Text* t);
+        // replaces all regular expression occurences by a static string
+        // \param regex The regular expression to search for
+        // \param replacement The string to replace the occurences with
+        // \param config The configuration for the regular expression
+        DLLEXPORT void regexReplace(const char* regex,
+            const char* replacement,
+            Regex::RegexConfig* config = 0);
+        // replaces all regular expression occurences with a result of a
+        // specified replacement function string \param regex The regular
+        // expression to search for \param replacementFunction a function that
+        // is called with the result of the regular expression and should return
+        // the replacement string \param config The configuration for the
+        // regular expression
+        DLLEXPORT void regexReplace(const char* regex,
+            std::function<Text(Regex::Result&)> replacementFunction,
+            Regex::RegexConfig* config = 0);
         //! Ersetzt einen bestimmten Textabschnitt mit einer anderen
         //! Zeichenkette
         //!  p1: Die Startposition des zu ersetzenden Textabschnittes
@@ -288,6 +318,11 @@ namespace Framework
         //! \param t Die Zeichenkette, nach der gesucht werden soll
         //! \return (true), wenn die Zeichenkette vorkommt. (false) sonnst
         DLLEXPORT bool hat(const char* t) const;
+        //! Überprüft, ob im Text eine bestimmte Zeichenkette vorkommt
+        //! \param searchStartIndex Der index ab dem gesucht werden soll
+        //! \param t Die Zeichenkette, nach der gesucht werden soll
+        //! \return (true), wenn die Zeichenkette vorkommt. (false) sonnst
+        DLLEXPORT bool hat(int searchStartIndex, const char* t) const;
         //! Überprüft, ob im Text der Inhalt eines anderen Textes vorkommt
         //! \param t Der Text, nach dessen Inhalt gesucht werden soll
         //! \return (true), wenn der Inhalt des Textes vorkommt. (false) sonnst
@@ -336,6 +371,11 @@ namespace Framework
         //! \param t Die Zeichenkette, die gefunden werden soll
         //! \return Die Position des ersten Vorkommens der Zeichenkette
         DLLEXPORT int positionVon(const char* t) const;
+        //! Gibt die erste Position einer bestimmten Zeichenkette im Text zurück
+        //! \param searchStart Index ab dem gesucht werden soll
+        //! \param t Die Zeichenkette, die gefunden werden soll
+        //! \return Die Position des ersten Vorkommens der Zeichenkette
+        DLLEXPORT int positionVon(int searchStart, const char* t) const;
         //! Gibt die erste Position eines Textinhaltes im Text zurück
         //! \param t Der Text, dessen Inhalt gefunden werden soll
         //! \return Die Position des ersten Vorkommens des Textinhaltes