Wer möchte ein Kolmogorov Komplexitätsgewinner sein?

22

Ihre heutige Mission ist es, einen Textkompressor zu erfinden.

Aufgabe

Sie werden zwei Funktionen schreiben:

  • Der Packer ist eine Funktion, die eine Zeichenfolge aus ASCII-Zeichen (U + 0000 bis U + 007F) akzeptiert und eine Unicode-Zeichenfolge (U + 0000 bis U + 10FFFF) mit möglichst wenigen Zeichen ausgibt.

  • Der Entpacker ist eine Funktion, die eine codierte Unicode-Zeichenfolge akzeptiert und genau die ursprüngliche ASCII-Zeichenfolge ausgibt.

Eingang

Die einzige autorisierte Eingabe ist die ASCII-Zeichenfolge (für den Packer) und die gepackte Unicode-Zeichenfolge (für den Entpacker). Keine Benutzereingabe, keine Internetverbindung, keine Verwendung des Dateisystems.

Ihre Funktionen können auf diese Liste englischer Wörter zugreifen . Sie können diese Liste als lokale TXT-Datei verwenden oder ihren Inhalt in Ihrem Quellcode als Zeichenfolge oder als Array von Zeichenfolgen kopieren .

Sie können die folgenden Ausschnitte in Ihren Funktionen nicht fest codieren.

Ausgabe

Die einzige autorisierte Ausgabe für beide Funktionen ist eine Zeichenfolge.

Die Ausgabe des Entpackers muss genau die gleichen Zeichen enthalten wie die Eingabe des Packers.

Ihre Ein- und Ausgänge können eine beliebige Zeichenkodierung verwenden, die alle Unicode-Zeichen unterstützt (UTF-8/16/32, GB18030, ...), da Ihre Punktzahl nur von der Anzahl der Unicode-Zeichen in der Ausgabe abhängt. Bitte geben Sie an, welche Codierung Sie verwenden.

Mit dem folgenden Tool können Sie die Anzahl der Unicode-Zeichen in Ihrer Ausgabe ermitteln: http://mothereff.in/byte-counter

Wertung

Ihr Eintrag muss in der Lage sein, die 10 folgenden Textausschnitte (die ich in diesem Forum aufgenommen habe) zu packen und zu entpacken.

Ihre Punktzahl ergibt sich aus der Summe der Größen Ihrer 10 gepackten Zeichenfolgen (in Unicode-Zeichen) und der Größe Ihrer beiden Funktionen (auch in Unicode-Zeichen).

Zählen Sie nicht die Größe des Wörterbuchs, wenn Sie es verwenden.

Bitte geben Sie in Ihren Einträgen die "Punktzahl" jedes Snippets und dessen gepackte Version an.

Die niedrigste Punktzahl gewinnt.

Daten

Hier sind die Codefragmente zur Berechnung Ihrer Punktzahl:

1: Rick Roll lyrics (1870b): Wir sind keine Fremden, um Golf zu kodieren, Sie kennen die Regeln und ich auch

Wir sind keine Fremden zu lieben
Sie kennen die Regeln und ich auch
Ein volles Engagement ist das, woran ich denke
Sie würden das von keinem anderen Kerl bekommen
Ich will dir nur sagen, wie ich mich fühle
Muss dich verstehen lassen

Gebe dich nie auf
Ich werde dich nicht enttäuschen
Ich werde niemals herumlaufen und dich im Stich lassen
Ich werde dich niemals zum Weinen bringen
Ich werde mich nie verabschieden
Ich werde niemals lügen und dich verletzen

Wir kennen uns schon so lange
Dein Herz hat geschmerzt, aber
Du bist zu schüchtern, um es zu sagen
Drinnen wissen wir beide, was los ist
Wir kennen das Spiel und werden es spielen
Und wenn Sie mich fragen, wie ich mich fühle
Sag mir nicht, dass du zu blind bist, um zu sehen

Gebe dich nie auf
Ich werde dich nicht enttäuschen
Ich werde niemals herumlaufen und dich im Stich lassen
Ich werde dich niemals zum Weinen bringen
Ich werde mich nie verabschieden
Ich werde niemals lügen und dich verletzen

Gebe dich nie auf
Ich werde dich nicht enttäuschen
Ich werde niemals herumlaufen und dich im Stich lassen
Ich werde dich niemals zum Weinen bringen
Ich werde mich nie verabschieden
Ich werde niemals lügen und dich verletzen

(Oh, gib dich auf)
(Oh, gib dich auf)
(Oh)
Niemals geben, niemals geben
(Gib dich auf)
(Oh)
Niemals geben, niemals geben
(Gib dich auf)

Wir kennen uns schon so lange
Dein Herz hat geschmerzt, aber
Du bist zu schüchtern, um es zu sagen
Drinnen wissen wir beide, was los ist
Wir kennen das Spiel und werden es spielen

Ich will dir nur sagen, wie ich mich fühle
Muss dich verstehen lassen

Gebe dich nie auf
Ich werde dich nicht enttäuschen
Ich werde niemals herumlaufen und dich im Stich lassen
Ich werde dich niemals zum Weinen bringen
Ich werde mich nie verabschieden
Ich werde niemals lügen und dich verletzen

Gebe dich nie auf
Ich werde dich nicht enttäuschen
Ich werde niemals herumlaufen und dich im Stich lassen
Ich werde dich niemals zum Weinen bringen
Ich werde mich nie verabschieden
Ich werde niemals lügen und dich verletzen

Gebe dich nie auf
Ich werde dich nicht enttäuschen
Ich werde niemals herumlaufen und dich im Stich lassen
Ich werde dich niemals zum Weinen bringen
Ich werde mich nie verabschieden
Ich werde niemals lügen und dich verletzen

2: Der Golfer (412b): Golf ASCII-art

      '\. . |> 18 >>
        \. '. |
       O >>. 'o |
        \. |
        / \. |
       / /. ' |
 jgs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^

3: die Zahl Diamant (233b): Drucken Sie diesen Diamanten

        1
       121
      12321
     1234321
    123454321
   12345654321
  1234567654321
 123456787654321
12345678987654321
 123456787654321
  1234567654321
   12345654321
    123454321
     1234321
      12321
       121
        1

4: Das Alphabet viermal (107b): Drucken Sie das Alphabet viermal aus

abcdefghijklmnopqrstuvwxyz
qwertyuiopasdfghjklzxcvbnm
pyfgcrlaoeuidhtnsqjkxbmwvz
zyxwvutsrqponmlkjihgfedcba

5: Old McDonald's Lyrics (203b): Alte MacDonald-Funktion

Der alte MacDonald hatte eine Farm, EIEIO,
Und auf dieser Farm hatte er eine Kuh, EIEIO,
Mit einem Moo Moo hier und einem Moo Moo dort,
Hier ein Moo, dort ein Moo, überall ein Moo Moo,
Der alte MacDonald hatte eine Farm, EIEIO!

6: Rock Around the Clock lyrics (144b): Rock Around the Clock

1, 2, 3 Uhr, 4 Uhr Rock,
5, 6, 7 Uhr, 8 Uhr Rock,
9, 10, 11 Uhr, 12 Uhr Rock,
Wir werden heute Abend rund um die Uhr rocken.

7: Hallo Welt (296b): Sagen Sie der Welt in ASCII-Kunst "Hallo"

 _ _ _ _ _ _ _
| | | | ___ | | | ___ __ _____ _ __ | | __ | | |
| | _ | | / _ \ | | / _ \ \ \ / \ / / _ \ | '__ | | / _` | |
| _ | __ / | | (_) | \ VV / (_) | | | | (_ | | _ |
| _ | | _ | \ ___ | _ | _ | \ ___ () \ _ / \ _ / \ ___ / _ | | _ | \ __, _ (_)
                    | /

8: Irischer Segen (210b): Ein alter irischer Segen

Möge die Straße aufsteigen, um dich zu treffen
Moege der Wind immer in deinem Ruecken sein
Möge die Sonne warm auf dein Gesicht scheinen
Der Regen fällt sanft auf deine Felder
Und bis wir uns wiedersehen
Möge Gott dich in seiner hohlen Hand halten

9: Es gab eine alte Dame Texte (1208b): Es gab eine alte Dame

Da war eine alte Dame, die eine Fliege verschluckt hat.  
Ich weiß nicht, warum sie diese Fliege verschluckt hat,  
Vielleicht stirbt sie.

Es gab eine alte Dame, die eine Spinne verschluckt hat,  
Das zappelte und zappelte und zappelte in ihr.  
Sie schluckte die Spinne, um die Fliege zu fangen,  
Ich weiß nicht, warum sie diese Fliege verschluckt hat,  
Vielleicht stirbt sie.

Es gab eine alte Dame, die einen Vogel verschluckt hat,  
Wie absurd, einen Vogel zu schlucken.  
Sie schluckte den Vogel, um die Spinne zu fangen,  
Sie schluckte die Spinne, um die Fliege zu fangen,  
Ich weiß nicht, warum sie diese Fliege verschluckt hat,  
Vielleicht stirbt sie.

Es gab eine alte Dame, die eine Katze verschluckt hat,  
Stellen Sie sich vor, Sie schlucken eine Katze.  
Sie schluckte die Katze, um den Vogel zu fangen,  
Sie schluckte den Vogel, um die Spinne zu fangen,  
Sie schluckte die Spinne, um die Fliege zu fangen,  
Ich weiß nicht, warum sie diese Fliege verschluckt hat,  
Vielleicht stirbt sie.

Es gab eine alte Dame, die einen Hund verschluckt hat,  
Was für ein Schwein, einen Hund zu schlucken.  
Sie schluckte den Hund, um die Katze zu fangen,  
Sie schluckte die Katze, um den Vogel zu fangen,  
Sie schluckte den Vogel, um die Spinne zu fangen,  
Sie schluckte die Spinne, um die Fliege zu fangen,  
Ich weiß nicht, warum sie diese Fliege verschluckt hat,  
Vielleicht stirbt sie.

Es gab eine alte Dame, die ein Pferd verschluckt hat,  
Sie ist natürlich gestorben.

10: Gettysburg-Adresse (1452b): Wie zufällig ist die Gettysburg-Adresse

Vor vier Jahren und sieben Jahren brachten unsere Väter auf diesem Kontinent eine neue Nation hervor, die in Freiheit gezeugt wurde und der Aussage verpflichtet war, dass alle Menschen gleich geschaffen sind. Jetzt befinden wir uns in einem großen Bürgerkrieg und prüfen, ob diese Nation oder irgendeine Nation, die so konzipiert und so engagiert ist, lange Bestand haben kann. Wir sind auf einem großen Schlachtfeld dieses Krieges getroffen. Wir sind gekommen, um einen Teil dieses Feldes als letzte Ruhestätte für diejenigen, die hier ihr Leben gaben, zu widmen, damit diese Nation leben könnte. Es ist insgesamt passend und richtig, dass wir dies tun sollten. Aber im weiteren Sinne können wir nicht widmen, wir können nicht weihen, wir können diesen Boden nicht heiligen. Die tapferen Männer, lebend und tot, die hier gekämpft haben, haben es geweiht, weit über unsere arme Macht, hinzuzufügen oder abzulenken. Die Welt wird sich weder merken noch lange daran erinnern, was wir hier sagen. aber es kann nie vergessen, was sie hier getan haben. Es ist vielmehr für uns, die Lebenden hier der unvollendeten Arbeit zu widmen, die die Kämpfer hier bisher so edel vorangetrieben haben. Es ist vielmehr unsere Aufgabe, uns hier der großen Aufgabe zu widmen, die vor uns liegt - dass wir uns von diesen geehrten Toten verstärkt der Sache widmen, für die sie das letzte volle Maß an Hingabe geleistet haben -, dass wir uns hier entschieden haben, dass diese Toten es nicht tun sollen umsonst gestorben, dass diese Nation unter Gott eine neue Geburt der Freiheit haben wird, und dass die Regierung des Volkes durch das Volk für das Volk nicht von der Erde zugrunde geht.

Insgesamt (unkomprimiert): 6135 Zeichen / Byte.

Habe Spaß!

xem
quelle
7
Es ist keine Herausforderung, eine Sprache zu erfinden, es ist eine Herausforderung, etwas zu komprimieren.
Justin
2
Ich denke, die Größe des Compilers / Executors (Compressors / Decompressors) in der Partitur nicht mit einzubeziehen, macht diese Herausforderung ein wenig offen. Irgendwann wird die Linie zwischen Wörterbuch und Hardcodierung sehr dünn.
Dennis
2
Verdammt, und hier habe ich bereits getippt private static final String RICK_ROLL_RETURN = "We're no strangers to love...
Graph Theory
1
Ich glaube nicht, dass Sie Dennis 'Beobachtung angesprochen haben.
Peter Taylor
1
@xem Ich denke, der Beitrag könnte verbessert werden, indem die Informationen in Abschnitte wie #Task, #Input, #Output, #Scoring unterteilt werden. Ich denke auch, dass die Größe des Quellcodes für den Kompressor und den Dekomprimierer in der Partitur enthalten sein sollte. Das schadet nichts, löst aber das Problem, auf das Dennis hingewiesen hat.
Rainbolt

Antworten:

6

Haskell - 5322 Punkte

Byte Code: 686

Originalgröße : 6147 = 1871+415+234+108+204+145+297+211+1209+1453

Codierte Größe: 4636 = 1396+233+163+92+153+115+197+164+979+1144

Ergebnis : 686+ 4636

Komprimierung der Zeichenanzahl: ~25%

Code

Abgesehen von Optimierungen werden hier Werte zwischen 0und 7fin Unicode-Zeichen als Hauptfaktoren gespeichert.

Die Anzahl der Bytes der codierten Ausgabe wird nicht verringert, sondern nur die Anzahl der Unicode-Zeichen. Zum Beispiel enthält Test # 4 108Zeichen und die codierte Ausgabe 92. Ihre jeweiligen Größen sind jedoch 108und 364Bytes.

import Data.Bits
import Data.List
import Data.Numbers.Primes
import qualified Data.Text as T
a=nub$concat$map(primeFactors)[0..127]
d(a:r)c=let s=shift c 5in if s<=0x10ffffthen d r(s+a)else c:d r a
d[]c=[c]
f(a:r)=let o=a.&.0x1fin(if o/=a then f((shiftR a 5):r)else f r)++[o]
f[]=[]
g=T.pack.map(toEnum).(\(a:r)->d r a).concatMap j.map(map(\x->head$elemIndices x a)).map(primeFactors.fromEnum).T.unpack
h=T.pack.map(toEnum.product.map((!!)a)).i.f.reverse.map(fromEnum).T.unpack
i(a:r)=let z=a`clearBit`4;x=if a`testBit`4then(take z$repeat$head r,tail r)else splitAt z r in[fst x]++i(snd x)
i[]=[]
j x@(a:_)=let l=length x in if(take l(repeat a))==x then[l`setBit`4,a]else[l]++x
j[]=[0]

Wie es funktioniert

  • Codierung

    1. Jedes Zeichen wird in sein numerisches Äquivalent umgewandelt. Rufen Sie diese Nummer an n.
    2. nwird dann in eine Liste ihrer Primfaktoren umgewandelt ps.
      • Es kommt zweckmäßigerweise vor, dass die Zahlen 0 bis 127 ausschließlich 32 gemeinsame Primfaktoren haben 1. Dies bedeutet, dass sie, die Faktoren, als Indizes mit nur 5 Bits gespeichert werden können.
      • 1 ist ein Sonderfall und wird durch eine leere Liste dargestellt.
    3. Mit ps der Kodierung kann jetzt begonnen werden.
      1. Jede Zahl von pswird in der Liste der 32 eindeutigen Faktoren in ihren Index umgewandelta ).
      2. (Denken Sie an dieser Stelle daran, dass es sich um eine Liste mit Indexen von Primfaktoren handelt.) Um mit dem nächsten Schritt fortzufahren, ps muss abgeflacht werden. Um die Integrität der Daten zu gewährleisten, wird jede Liste in eine andere Liste mit zwei Teilen konvertiert
        1. Das erste Element speichert seine Länge und setzt sich aus demselben Faktor zusammen.
          • Es gibt höchstens 6 Primfaktoren pro Liste, diese Information wird auf den äußersten rechten 3 Bits gespeichert. Das fünfte Bit wird als Flag verwendet, um anzuzeigen, ob die Liste aus einem einzelnen Faktor besteht.
        2. Die übrigen Elemente sind die Indizes selbst oder ein einzelner Index, wenn die Liste weniger als zwei verschiedene Faktoren enthält.
      3. Diese Listen werden dann zu einer einzigen abgeflachten Liste verkettet fs.
    4. Die Elemente von fskönnen dann durch Bitverschiebung in Unicode-Zeichen gepackt werden.
  • Dekodierung

    • Führen Sie die Codierungsschritte in umgekehrter Reihenfolge durch.
    • Wenn Sie sich fragen, wie das 1passt, möchte ich Sie daran erinnern product [] == 1.

Tests

Das Verwenden dieser Schnittstelle zum Testen wäre schmerzhaft. Daher habe ich diese Funktion verwendet, um die folgenden Ergebnisse bereitzustellen.

edTest f = do
    t <- readFile f
    let txt = T.pack t
        enc = g txt
        dec = h enc
        tst = txt == dec
    putStrLn $ (show $ T.length txt) ++ "," ++ (show $ T.length enc) ++ "," ++ (show $ T.length dec)++","++(show tst)
    putStrLn $ if not tst then T.unpack txt ++ "\n---NEXT---\n" ++ T.unpack dec else ""


λ> edTest "1"
1871,1396,1871,True

λ> edTest "2"
412,233,412,True

λ> edTest "3"
234,163,234,True

λ> edTest "4"
108,92,108,True

λ> edTest "5"
204,153,204,True

λ> edTest "6"
145,115,145,True

λ> edTest "7"
297,197,297,True

λ> edTest "8"
211,164,211,True

λ> edTest "9"
1209,979,1209,True

λ> edTest "10"
1453,1144,1453,True

Probe

Die Ausgabe der Codierungsfunktion gfür Test Nr. 4 ist dies
"\99429\582753\135266\70785\35953\855074\247652\1082563\68738\49724\164898\68157\99429\67973\1082404\587873\73795\298017\330818\198705\69861\1082435\595009\607426\36414\69873\855074\265249\346275\67779\68738\77985\1082513\821353\132131\101410\247652\1082562\49724\164898\67649\594977\34915\67746\50273\135265\103997\563265\103457\1086021\99399\584802\70753\73889\34882\582722\411459\67779\68740\1084516\1082563\1091681\103491\313282\49724\164897\68705\135741\69858\50241\607426\35905\608421\1082435\69858\50274\71777\43075\298018\280517\1082404\67971\36017\955425\67665\919600\100452\132129\214883\35057\856097\101474\70753\135737"
oder, wenn Sie ein Kenner des Kauderwels sind, dies
𘑥򎑡𡁢𑒁豱󐰢𼝤􈓃𐲂숼𨐢𐨽𘑥𐦅􈐤򏡡𒁃񈰡񐱂𰠱𑃥􈑃򑑁򔓂踾𑃱󐰢񀰡񔢣𐣃𐲂𓂡􈒑󈡩𠐣𘰢𼝤􈓂숼𨐢𐡁򑐡衣𐢢쑡𡁡𙘽򉡁𙐡􉉅𘑇򎱢𑑡𒂡衂򎑂񤝃𐣃𐲄􈱤􈓃􊡡𙑃񌟂숼𨐡𐱡𡈽𑃢쑁򔓂豁򔢥􈑃𑃢쑢𑡡ꡃ񈰢񄟅􈐤𐦃貱󩐡𐡑󠠰𘡤𠐡𴝣裱󑀡𘱢𑑡𡈹

Zusätzliche Hinweise

  • Mit http://mothereff.in/byte-counter , Verzeichnislisten undedTest die Größe der Tests alle konsistent, unterscheiden sich jedoch immer noch von der in der Frage angegebenen Größe.
  • 10 Test # enthält ein paar EM Bindestriche ( ) , dass ich mit ersetzt , -da sie außerhalb des 0- 7fBereich.
  • Eine weitere Komprimierung könnte unter Verwendung des verbleibenden vierten Bits während des Reduzierens erreicht werden, zum Beispiel 00Basisfall, 01Alles 10wiederholen , Wiederholen mit Ausnahme des Letzten, 11Wiederholen mit Ausnahme der letzten zwei.
  • Die Testdateien und der Code sind alle hier verfügbar: https://github.com/gxtaillon/codegolf/tree/master/Kolmogorov
Gxtaillon
quelle
Hallo, danke für diese Antwort! :) Ich verstand nicht , was in binärer passiert , wenn Sie konvertieren abcdefghijklm...zu 𘑥򎑡𡁢𑒁豱󐰢𼝤..., könnte man es erklären , ein wenig mehr , bitte? Außerdem habe ich die Zeichenanzahl korrigiert und die Gedankenstriche in # 10 in der Frage umgewandelt. Meine Charcounts sind aber immer noch anders als deine. Keine Ahnung warum, ich habe das Tool mothereff.in verwendet.
xem
@xem Die komplizierten Details wurden enthüllt.
Gxtaillon
Mein Verstand ist (bildlich) buchstäblich durch die Idee, dass die Zahlen 0 und 2-127 auf 5 Bits codiert werden können, durchgebrannt. Haben Sie das selbst gefunden oder war es etwas bekannt? Bonusfrage: Wie viele Bits benötigen Sie, um nur die druckbaren ASCII-Zeichen zu speichern, dh 95 verschiedene Zeichen?
xem
@xem Die Zahlen sind nicht mit 5 Bits codiert, jeder ihrer Faktoren ist. Ich würde mich sehr freuen, wenn ich einen Weg gefunden hätte, 7 Bits auf nur 5 zu kodieren. Was ASCII-Zeichen betrifft, so würden sie mit dieser Methode immer noch jeweils 5 Bits benötigen.
Gxtaillon
1
Da es in dem von Ihnen angegebenen Bereich höchstens 6 Faktoren pro Zahl gibt, verwendet die Länge 3 von 5 Bits "Block". Dann werden die Indizes mit 5 Bits codiert, ja. In dieser Implementierung wird eines der 2 nicht verwendeten Bits im Längenblock verwendet, um zusätzliche Komprimierung zu erhalten.
Gxtaillon
4

C ++ (C ++ 11), 2741 Punkte

Diese Antwort verwendet UTF-32 als Kodierung für den komprimierten Text.

#include <cstdio>
#include <iostream>
#include <locale>
#include <string>
#define L locale
using namespace std;long b,n,i,l;void c(){string d;char x;while((x=cin.get())!=EOF)d+=x;b=(d.size()*7)%20;n=5;wcout.imbue(L());for(char y:d){b=b<<7|y&127;n+=7;if(n>=20)wcout.put(b>>(n-=20)&0xFFFFF);}if(n)wcout.put(b<<20-n&0xFFFFF);}void d(){wstring d;wchar_t w;wcin.imbue(L());while((w=wcin.get())!=EOF)d+=w;l=-1;for(wchar_t y:d){b=b<<20|y;n+=20;if(l<0)l=b>>15&31,n-=5;while(n>=7&(i<d.size()-1|n>20-l))cout.put(b>>(n-=7)&127);++i;}}int main(int t,char**a){L::global(L("en_US.utf8"));**++a<'d'?c():d();}

Char zählt und erzielte

Code: 593 Zeichen (der abschließende Zeilenumbruch wird entfernt)

Komprimierte Texte (Unicode-Zeichen) : 654 + 145 + 82 + 38 + 51 + 104 + 73 + 423 + 506 = 2148 (gezählt mit wc -mder Anzahl der Unicode-Zeichen anstelle von Bytes, die Anzahl der Bytes ist wie bei der Antwort von @ gxtaillon , höher als die Originale, insgesamt 8413 Bytes, gezählt mit wc -c).

Komprimierungsrate (ASCII zu Unicode) : 35,01% (unter Verwendung der 6135 Bytes aus der Frage (wie wc -c))

In acht nehmen:

Viele Shells können die von diesem Programm erzeugten Unicode-Zeichen nicht verarbeiten. Das Dekomprimieren kann daher dazu führen, dass der Text an einer Stelle abgeschnitten wird, an der die Shell kein Zeichen verarbeiten kann, da die Eingabe über stdindie Shell erfolgt.

Kompilieren

Es sollte mit clang++und kompiliert g++ -std=c++11werden, zeigt jedoch einige Warnungen zur Priorität des Operators an, da ein Ausdruck wie b<<20-n&0xFFFFFnicht ((b << 20) - n) & 0xFFFFFwie erwartet, sondern wie behandelt wird(b << (20 - n)) & 0xFFFFF .

Verwendung

  • Kompilieren Sie das Programm in eine ausführbare Datei, z ./compress .
  • Führen Sie das Programm ./compress czum Komprimieren oder ./compress dDekomprimieren aus. (Vorsicht, wenn Sie die Option weglassen, erhalten Sie ein SEGFAULT (die Fehlerprüfung ist so zeichenintensiv ...) und andere Optionen (z. B. using Danstelle vond ) können zu unerwarteten Ergebnissen führen
  • Der Eingang wird gelesen stdinund der Ausgang beschriebenstdout

Wie es funktioniert

Ungolfed

#include <cstdio>
#include <iostream>
#include <locale>
#include <string>

using namespace std;

long b, n, i, l;

// Compress
void c() {
    string d;
    char x;
    // Read from STDIN until EOF
    while((x = cin.get()) != EOF)
        d += x;
    // Calculate the number of bits used from the last unicode character
    // (maximum 19) and store it into the first 5 bits
    b = (d.size() * 7) % 20;
    n = 5;
    // Set the output locale to allow unicode
    wcout.imbue(locale());
    // For each character in the input...
    for (char y : d) {
        // Add its bit representation (7 bits) to the right of the buffer
        // by shifting the buffer left and ORing with the character code
        b = (b << 7) | (y & 127);
        // Add 7 to the bit counter
        n += 7;
        // If enough data is present (20 bits per output character),
        // calculate the output character by shifting the buffer right,
        // so that the last 20 bits are the left 20 bits of the buffer.
        // Also decrement the bit counter by 20, as 20 bits are removed.
        if (n >= 20)
            wcout.put((b >> (n -= 20)) & 0xFFFFF);
    }
    // If there are still bits in the buffer, write them to the front of
    // another unicode character
    if (n)
        wcout.put((b << (20 - n)) & 0xFFFFF);
}

// Decompress
void d() {
    wstring d;
    wchar_t w;
    // Set STDIN to UNICODE
    wcin.imbue(locale());
    // Read wide characters from STDIN (std::wcin) until EOF
    while ((w = wcin.get()) != EOF)
        d += w;
    // `l' represents the number of bits used in the last unicode character.
    // It will be set later
    l = -1;
    // For each input character...
    for (wchar_t y : d) {
        // Add it to the buffer and add 20 to the bit counter
        b = (b << 20) | y;
        n += 20;
        // If the number of bits in the last unicode character has not been
        // set yet, read the first 5 buffer bits into `l'. This is
        // necessary because the last character may contain more than 7
        // (one entire uncompressed character) unused bits which may
        // otherwise be interpreted as garbage.
        if (l < 0) {
            l = (b >> 15) & 31;
            n -= 5;
        }
        // As long as there is data to turn into output characters
        // (at least 7 bits in the buffer and either not the last
        // unicode character or before the unused bits)
        while (n >= 7 && ((i < d.size() - 1) || (n > (20 - l)))
            cout.put((b >> (n -= 7)) & 127); // Output the left 7 bits in the buffer as an ASCII character
        ++i; // Increment the character index, so that we know when we reach the last input character
    }
}
int main(int t, char**a) {
    // Set the default locale to en_US.utf8 (with unicode)
    locale::global(locale("en_US.utf8"));
    // Decide whether to compress or decompress.
    // This is just fancy pointer stuff for a[1][0] < 'd' ? c() : d()
    (**(++a) < 'd') ? c() : d();
}

Erläuterung

Da alle Unicode-Zeichen von U+0000bis U+10FFFFzulässig sind, können 20 Bit pro Unicode-Zeichen verwendet werden:U+FFFFF Zeichen verwendet werden Verwendet 20 Bit und ist weiterhin im zulässigen Bereich enthalten. Daher versuchen wir nur, alle einzelnen ASCII-Zeichenbits in die Unicode-Zeichen zu packen, um mehrere ASCII-Zeichen in einem Unicode-Zeichen zu speichern. Wir müssen jedoch auch die Anzahl der im letzten Unicode-Zeichen verwendeten Bits speichern, da nicht verwendete Garbage-Bits andernfalls als ordnungsgemäß komprimierte ASCII-Zeichen interpretiert werden können. Da die maximale Anzahl verwendeter Bits im letzten Unicode-Zeichen 20 beträgt, benötigen wir dafür 5 Bits, die am Anfang der komprimierten Daten stehen.

Beispielausgabe

Dies ist die Ausgabe von Beispiel 4 (wie von angegeben less):

<U+4E1C5><U+8F265><U+CD9F4><U+69D5A><U+F66DD><U+DBF87><U+1E5CF><U+A75ED>
<U+DFC79><U+F42B8><U+F7CBC><U+BA79E><U+BA77F>쏏𦛏<U+A356B><U+D9EBC><U+63ED8>
<U+B76D1><U+5C3CE><U+6CF8F><U+96CC3><U+BF2F5><U+D3934><U+74DDC><U+F8EAD>
<U+7E316><U+DEFDB><U+D0AF5><U+E7C77><U+EDD7A><U+73E5C><U+786FD><U+DB766>
<U+BD5A7><U+467CD><U+97263><U+C5840>

( 쏏𦛏Geben Sie <U+C3CF><U+266CF>als Zeichencodes an, aber ich hätte das vielleicht falsch verstanden.)

hlt
quelle
2

Python 3, 289 + 818 = 1107 Punkte

Nur leicht golfen.

import zlib as Z
def p(s):
 z=int.from_bytes(Z.compress(s),'big');o=''
 while z:
  z,d=divmod(z,1<<20)
  if d>0xd000:d+=1<<16
  o+=chr(d)
 return o[::-1]
def u(s):
 i=0
 for c in s:
  d=ord(c)
  if d>0xe000:d-=1<<16
  i=(i<<20)+d
 return Z.decompress(i.to_bytes(i.bit_length()//8+1,'big'))

Die Gesamtcodegröße beträgt 289 Bytes und codiert die angegebenen 6135 Bytes in 818 Unicode-Zeichen. Die Gesamtanzahl der ausgegebenen Bytes beträgt 3201 Bytes und ist damit erheblich kleiner als die ursprünglichen Eingaben.

Codiert mit zlib und anschließend mit Unicode-Codierung. Es war eine zusätzliche Logik erforderlich, um Ersatzzeichen zu vermeiden (die Python wirklich hasst).

Beispielausgabe von # 4 aus Sicht von less(37 Unicode-Zeichen):

x<U+AC0DC><U+BB701><U+D0200><U+D00B0><U+AD2F4><U+EEFC5>𤆺<U+F4F34>멍<U+3C63A><U+2F62C><U+BA5B6><U+4E70A><U+F7D88><U+FF138><U+40CAE>
<U+CB43E><U+C30F5><U+6FFEF>𥠝<U+698BE><U+9D73A><U+95199><U+BD941><U+10B55E><U+88889><U+75A1F><U+4C4BB><U+5C67A><U+1089A3><U+C75A7>
<U+38AC1><U+4B6BB><U+592F0>ᚋ<U+F2C9B>

Treiberprogramm zum Testen:

if __name__ == '__main__':
    import os
    total = 0
    for i in range(1,10+1):
        out = p(open('data/%d.txt'%i,'rb').read())
        total += len(out)
        open('out/%d.bin'%i,'w',encoding='utf8').write(out)
    print(total)
    for i in range(1,10+1):
        out = u(open('out/%d.bin'%i,'r',encoding='utf8').read())
        open('data2/%d.txt'%i,'wb').write(out)

Anzahl der Ausgangsbytes:

 607 out/1.bin
 128 out/2.bin
 101 out/3.bin
 143 out/4.bin
 177 out/5.bin
 145 out/6.bin
 186 out/7.bin
 222 out/8.bin
 389 out/9.bin
1103 out/10.bin
3201 total
nneonneo
quelle
1
Ist das nicht die Tatsache, dass hier eine Komprimierungsbibliothek verwendet wird, die ein bisschen schummelt?
Beta Decay
@BetaDecay: Es schränkt das in der Frage nicht ein, also dachte ich, es sei faires Spiel.
Nneonneo
Außerdem müssen Sie einen Dekomprimierer einbinden.
Beta Decay
@BetaDecay: Ist pder Packer, uist der Entpacker.
Nneonneo
1

Python 2 - 1141 Punkte

from zlib import *;v=256
def e(b):
 x=0
 for c in compress(b,9):x=(x*v)+ord(c)
 b=bin(x)[2:]
 return "".join(unichr(int("1"+b[a:a+19],2))for a in range(0,len(b),19))
def d(s):
 y=int("".join(bin(ord(a))[3:]for a in s),2);x=""
 while y:y,d=(y/v,chr(y%v));x=d+x
 return decompress(x)

Die Codegröße ist 281Byte und codiert die 6135Bytes in 860Unicode-Zeichen.

Wie es funktioniert:

Um zu kodieren:

  1. Komprimieren Sie die zu codierende Zeichenfolge.
  2. Interpretieren Sie die komprimierte Zeichenfolge als Basis-256-Zahl.
  3. Wandle die Zahl in eine Binärzahl um.
  4. Teilen Sie die Binärdatei in 19Bitgruppen auf, fügen Sie 1am Anfang jedes Bits ein Bit hinzu und konvertieren Sie sie dann in Unicode-Zeichen.

Dekodierung ist das Gegenteil.

Beachten Sie, dass einige Python-Versionen nur Unicode-Zeichen bis zu verarbeiten 0xFFFFkönnen und dieser Code daher a auslöst ValueError.

Pfeffer
quelle