[C++] RLE mit Zahlen
-
Hey Community!
Ich habe da mal eine Frage, und zwar habe ich schon viel herausgefunden, allerdings nicht das was ich suche. Ich habe in C++ eine Klasse geschrieben, welche mit der RLE einen Text komprimieren kann. Jetzt habe ich nur noch das Problem, dass wenn Zahlen im Text vorkommen ich Probleme bekomme^^
Also z.B. dieser String wird dekodiert:
„AAAAAAGGH!”
Ergebnis:
„6AGGH!” (Da 1en eine Vergrößerung bringen und 2en unnötig sind werden beide nicht davorgeschrieben)Also die Klasse funktioniert so, dass sie bei dem encoding den übergebenen String in ein Char-Array umwandelt und so einzelnd die Zeichen durchgehen kann. Bei diesem String:
„AAA111B”
würde aber folgendes rauskommen:
„3A31B”
Und das würde bei der Dekodierung zu diesem Ergebnis führen:
AAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBWie kann ich das Problem lösen und auch Zahlen korrekt codieren und dekodieren?
LG
-
Deine Probleme und mögliche Lösungen werden hier ausführlich anhand von Beispielen erläutert:
http://de.wikipedia.org/wiki/Lauflängenkodierung
-
Dann musst du wohl Zahlen im Inputstring irgendwie
- verbieten
- kenntlich machen ("Steuerzeichen" --> das darf dann sonst nicht vorkommen oder muss auch kenntlich gemacht werden)Das geht zum bsp so:
"Abbbbccccc3333deEF`````" --> "Abbbbccccc`3`3`3`3deEF``````````" --> "A4b5c4`3deEF5``"
` heisst dann "nimm das nächste Zeichen buchstabengetreu" --> führt aber zu verkompiziertem Parsen
-
Wenn man sich die ASCII-Tabelle ansieht, sieht man, dass die Werte drei bis acht Steuerzeichen sind, die in einem normalen Text nicht vorkommen. So kannst du also einfach Wiederholungen von drei bis acht Zeichen kodieren. Falls das nicht ausreichen sollte und du im ASCII-Bereich bleiben willst, dann kannst du dir auch eine andere Eigenschaft von ASCII zur Hilfe nehmen. ASCII-Code ist nur 7Bit breit, das oberste Bit ist also frei. Bei UTF8 wird es zur Erkennung genutzt, ob es ein Mehrbytezeichen ist. Damit kannst du aber selber Werte bis 127 oder 129, wenn du 0 und 1 außen vor lässt, kodieren.
-
Erstmal danke für die schnelle Hilfe

Hm.. also mit Markerzeichen davor, fände ich sehr unsauber..
@Paul Müller
Versteht ich net.. soll ich jetzt anstatt 1,2,3,4,5,6,7,8,9 Steuerzeichen aus der ASCII Tabelle benutzen? Wäre echt super, wenn du mir ien Beispiel geben könntest
Falls ihr den Code der Klasse braucht, dann sagt Bescheid (:
LG
-
C++Tester schrieb:
Hm.. also mit Markerzeichen davor, fände ich sehr unsauber..
Warum? Was wäre der Unterschied zur jetzigen Sonderbedeutung von Ziffern? Damit erschlägst du mit einem Mal alle Probleme.
-
Weil dann die der String wieder größer wird

-
C++Tester schrieb:
Weil dann die der String wieder größer wird

Tja, das ist nun einmal eine Eigenschaft von RLE.
-
C++Tester schrieb:
Hm.. also mit Markerzeichen davor, fände ich sehr unsauber..
Damit stände dir aber der volle Bereich von char zur Verfügung.
C++Tester schrieb:
@Paul Müller
Versteht ich net.. soll ich jetzt anstatt 1,2,3,4,5,6,7,8,9 Steuerzeichen aus der ASCII Tabelle benutzen? Wäre echt super, wenn du mir ien Beispiel geben könntest
Die Druckbaren Zeichen beginnen ja nicht gleich am Anfang des ASCII-Tabelle. Und ein Wertebereich von 3 bis 8 wäre ja schon mal eine Maßnahme. Die Idee ist einfach die, Zeichen zu nutzen, die in deiner Zeichenfolge nicht vorkommen.
C++Tester schrieb:
Falls ihr den Code der Klasse braucht, dann sagt Bescheid (:
Viel interessanter wäre es, wenn du uns verrätst, was du genau kodieren willst und warum. Vielleicht gibt es noch andere Dinge zu beachten, auf die du selbst nicht kommst.
-
SeppJ schrieb:
C++Tester schrieb:
Weil dann die der String wieder größer wird

Tja, das ist nun einmal eine Eigenschaft von RLE.
Hehe, das stimmt natürlich, trotzdem kann man versuchen Sie so klein wie möglich zu halten

@Paul Müller
Okay, also den Zähler (2A4
vor Zahlen durch , , , usw.. ersetzen? Okay, dann ändere ich das kurz und melde mich wieder 
Der Code ist eig. nur für mich, ich bin gerade dabei C++ zu lernen und dann macht man zwischendurch halt ein paar Projekte um zu sehen was man kann

-
C++Tester schrieb:
Der Code ist eig. nur für mich
Dann versuch es gar nicht. Rein theoretisch gibt sich da nichts und es hat den Vorteil, dass du dir die codierte Datei einfach anschauen kannst.
-
Du kannst den gesamten Text in RLE-Blöcke und nicht RLE-Blöcke aufteilen. Am Anfang gibst du immer die Länge des Blocks an (mit fixer Stellenzahl*), dann ein einzelnes Bit, das angibt, ob der Block als RLE-Block zu verstehen ist oder nicht und dann der Blockinhalt (je nachdem ein einzelnes Zeichen oder x unkodierte Zeichen).
* mit mindestens einem Escapewert, der angibt, dass eine weitere Länge mit größerer (oder gleicher) Stellenanzahl folgt. So könntest du 0-8 als Werte verwenden, 9 als Escapewert, worauf eine zweistellige Länge folgt. Die Länge 20 könnte damit z.B. als 920 kodiert werden (oder auch 911, wenn du nichts vom Wertebereich verschwenden möchtest).
AAAAAAAAAAAAGGH!111111wird dann zu9030A41GGH!601.Sinnvollerweise machst du das binär, dann kannst du in einem Byte 256 statt 10 verschiedene Werte unterbringen. Damit könntest du 0-126 als Werte verwenden, 127 als Escapewert und das restliche Bit als RLE-Marker, was doch weitaus ökonomischer ist.
Das fertige Programm mag keinen wirklichen Nutzen haben, aber wenigstens wirst du hinterher etwas sattelfester in Bitspielereien sein.
-
So, fertig, funktioniert, hab jetzt doch die Methode genommen einen Marker Char zu setzen..^^ Wenn eine Zahl im String ist, setze ich \003 davor und bei den Überprüfungen handle ich dann entsprechend.
Danke für eure Hilfe!
-
#include <string> #include <iostream> #include <sstream> std::string Decode(const std::string& input); std::string Encode(const std::string& input); int main() { std::string input = "AAA111B"; std::cout << input << std::endl; std::string res = Encode(input); std::cout << res << std::endl; std::cout << Decode(res) << std::endl; return 0; } std::string Decode(const std::string& input) { std::string result; for (size_t i = 0; i < input.length(); ++i) { if (input[i] == '\1') { result += input[++i]; } else if (isdigit(input[i])) { char c = (input[i + 1] == '\1' ? input[i + 2] : input[i + 1]); for (size_t j = 1; j < (size_t) input[i] - '0'; ++j) { result += c; } } else { result += input[i]; } } return result; } std::string Encode(const std::string& input) { std::string result; int count = 1; for (size_t i = 0; i < input.length(); ++i) { if (input[i + 1] == input[i]) { ++count; } else { if (count > 2 && count <= 9) { result += count + '0'; } if (isdigit(input[i])) { result += '\1'; } if (count == 2) { result += input[i]; } result += input[i]; count = 1; } } return result; }Zahlen werden maskiert. Wie bereits angesprochen bringt das alles aber keinen großen Vorteil. Bei Zahlen wird der Ausgabetext sogar größer, als das Original.
-
@köklökl
Wie geil, hab das fast haargenau so gemacht wie du