Chi vuole essere un vincitore della complessità di Kolmogorov?


22

La tua missione oggi è inventare un compressore di testo.

Compito

Scriverai due funzioni:

  • Il packer è una funzione che accetta una stringa di caratteri ASCII (da U + 0000 a U + 007F) e genera una stringa Unicode (da U + 0000 a U + 10FFFF), contenente il minor numero possibile di caratteri.

  • L'unpacker è una funzione che accetta una stringa Unicode codificato ed emette esattamente la stringa ASCII originale.

Ingresso

L'unico input autorizzato è la stringa ASCII (per il packer) e la stringa Unicode compressa (per il decompressore). Nessun input dell'utente, nessuna connessione a Internet, nessun utilizzo del file system.

Le tue funzioni possono avere accesso a questo elenco di parole inglesi . È possibile utilizzare questo elenco come file txt locale o copiarne il contenuto nel codice sorgente come stringa o matrice di stringhe .

Non puoi codificare i frammenti di seguito nelle tue funzioni.

Produzione

L'unico output autorizzato per entrambe le funzioni è una stringa.

L'output di unpacker deve contenere esattamente gli stessi caratteri dell'input del packer.

I tuoi input e output possono utilizzare qualsiasi codifica di caratteri che supporti tutti Unicode (UTF-8/16/32, GB18030, ...), poiché il tuo punteggio dipenderà solo dal numero di caratteri Unicode nell'output. Per favore, precisa quale codifica stai usando.

Per contare il numero di caratteri Unicode nel tuo output, puoi usare questo strumento: http://mothereff.in/byte-counter

punteggio

La tua voce deve essere in grado di impacchettare e decomprimere i seguenti 10 frammenti di testo (che ho preso su questo forum).

Il tuo punteggio sarà la somma delle dimensioni delle tue 10 stringhe impaccate (in caratteri Unicode) + la dimensione delle tue due funzioni (anche in caratteri Unicode)

Non contare le dimensioni del dizionario se lo usi.

Includi nelle voci il "punteggio" di ogni frammento e la loro versione compressa.

Il punteggio più basso vince.

Dati

Ecco i frammenti da codificare per calcolare il tuo punteggio:

1: testo di Rick Roll (1870b): non siamo estranei al codice del golf, conosci le regole e anche io

Non siamo estranei all'amore
Conosci le regole e anche io
Un impegno pieno è quello a cui sto pensando
Non lo capiresti da nessun altro ragazzo
Voglio solo dirti come mi sento
Devo farti capire

Non ti lascerà mai stare
Non ti deluderò mai
Non correre mai in giro e abbandonarti
Non ti farò mai piangere
Non dirò mai addio
Non dire mai una bugia e farti del male

Ci conosciamo da tanto tempo
Il tuo cuore ha sofferto ma
Sei troppo timido per dirlo
All'interno sappiamo entrambi cosa sta succedendo
Conosciamo il gioco e lo giocheremo
E se mi chiedi come mi sento
Non dirmi che sei troppo cieco per vedere

Non ti lascerà mai stare
Non ti deluderò mai
Non correre mai in giro e abbandonarti
Non ti farò mai piangere
Non dirò mai addio
Non dire mai una bugia e farti del male

Non ti lascerà mai stare
Non ti deluderò mai
Non correre mai in giro e abbandonarti
Non ti farò mai piangere
Non dirò mai addio
Non dire mai una bugia e farti del male

(Ooh, arrenditi)
(Ooh, arrenditi)
(Ooh)
Mai dare, mai dare
(Ti arrendo)
(Ooh)
Mai dare, mai dare
(Ti arrendo)

Ci conosciamo da così tanto tempo
Il tuo cuore ha sofferto ma
Sei troppo timido per dirlo
All'interno sappiamo entrambi cosa sta succedendo
Conosciamo il gioco e lo giocheremo

Voglio solo dirti come mi sento
Devo farti capire

Non ti lascerà mai stare
Non ti deluderò mai
Non correre mai in giro e abbandonarti
Non ti farò mai piangere
Non dirò mai addio
Non dire mai una bugia e farti del male

Non ti lascerà mai stare
Non ti deluderò mai
Non correre mai in giro e abbandonarti
Non ti farò mai piangere
Non dirò mai addio
Non dire mai una bugia e farti del male

Non ti lascerà mai stare
Non ti deluderò mai
Non correre mai in giro e abbandonarti
Non ti farò mai piangere
Non dirò mai addio
Non dire mai una bugia e farti del male

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

      '\. . |> 18 >>
        \. '. |
       O >>. 'o |
        \. |
        / \. |
       / /. " |
 JGS ^^^^^^^ `^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^

3: the number diamond (233b): stampa questo diamante

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

4: l'alfabeto quattro volte (107b): stampa l'alfabeto quattro volte

abcdefghijklmnopqrstuvwxyz
qwertyuiopasdfghjklzxcvbnm
pyfgcrlaoeuidhtnsqjkxbmwvz
zyxwvutsrqponmlkjihgfedcba

5: Old McDonald's lyrics (203b): Old MacDonald function

Il vecchio MacDonald aveva una fattoria, EIEIO,
E in quella fattoria aveva una mucca, EIEIO,
Con un moo moo qui e un moo moo lì,
Qui un muggito, un muggito, ovunque un muggito,
Il vecchio MacDonald aveva una fattoria, EIEIO!

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

1, 2, 3 in punto, 4 in punto rock,
5, 6, 7 in punto, 8 in punto rock,
9, 10, 11 in punto, 12 in punto rock,
Stasera suoneremo tutto il giorno.

7: Hello World (296b): Dì "Ciao" al mondo nell'arte ASCII

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

8: Irish blessing (210b): una vecchia benedizione irlandese

Possa la strada salire per incontrarti
Che tu abbia sempre il vento in poppa
Possa il sole splendere caldo sul tuo viso
Le piogge cadono morbide sui tuoi campi
E fino a quando ci incontreremo di nuovo
Possa Dio trattenerti nell'incavo della sua mano

9: C'era una vecchia signora lyrics (1208b): C'era una vecchia signora

C'era una vecchia signora che ingoiò una mosca.  
Non so perché abbia ingoiato quella mosca,  
Forse morirà.

C'era una vecchia signora che ingoiò un ragno,  
Che si agitava, si agitava e si agitava dentro di lei.  
Ha ingoiato il ragno per catturare la mosca,  
Non so perché abbia ingoiato quella mosca,  
Forse morirà.

C'era una vecchia signora che ingoiò un uccello,  
Che assurdo inghiottire un uccello.  
Ha ingoiato l'uccello per catturare il ragno,  
Ha ingoiato il ragno per catturare la mosca,  
Non so perché abbia ingoiato quella mosca,  
Forse morirà.

C'era una vecchia signora che ingoiò un gatto,  
Immagina di ingoiare un gatto.  
Ha ingoiato il gatto per catturare l'uccello,  
Ha ingoiato l'uccello per catturare il ragno,  
Ha ingoiato il ragno per catturare la mosca,  
Non so perché abbia ingoiato quella mosca,  
Forse morirà.

C'era una vecchia signora che ingoiò un cane,  
Che maiale inghiottire un cane.  
Ha ingoiato il cane per catturare il gatto,  
Ha ingoiato il gatto per catturare l'uccello,  
Ha ingoiato l'uccello per catturare il ragno,  
Ha ingoiato il ragno per catturare la mosca,  
Non so perché abbia ingoiato quella mosca,  
Forse morirà.

C'era una vecchia signora che ingoiò un cavallo,  
È morta ovviamente.

10: indirizzo gettysburg (1452b): quanto è casuale l'indirizzo di Gettysburg

Quattro punti e sette anni fa i nostri padri hanno prodotto in questo continente una nuova nazione, concepita in libertà e dedicata alla proposizione che tutti gli uomini sono creati uguali. Ora siamo impegnati in una grande guerra civile, verificando se quella nazione, o qualsiasi nazione così concepita e così dedicata, possa durare a lungo. Ci siamo incontrati su un grande campo di battaglia di quella guerra. Siamo venuti per dedicare una parte di quel campo, come luogo di riposo finale per coloro che qui hanno dato la vita affinché quella nazione potesse vivere. È del tutto appropriato e corretto che dovremmo farlo. Ma, in senso lato, non possiamo dedicare, non possiamo consacrare, non possiamo santificare questo terreno. Gli uomini coraggiosi, vivi e morti, che hanno lottato qui, lo hanno consacrato, molto al di sopra del nostro povero potere di aggiungere o detrarre. Il mondo noterà poco, né ricorderà a lungo ciò che diciamo qui, ma non potrà mai dimenticare quello che hanno fatto qui. Spetta a noi i vivi, piuttosto, dedicarsi qui all'opera incompiuta che finora hanno combattuto nobilmente coloro che hanno combattuto qui. È piuttosto per noi essere qui dedicati al grande compito che ci rimane davanti - che da questi onorati morti prendiamo maggiore devozione a quella causa per la quale hanno dato l'ultima misura piena di devozione - che qui risolviamo altamente che questi morti non devono sono morti invano - che questa nazione, sotto Dio, avrà una nuova nascita di libertà - e che il governo del popolo, da parte del popolo, per il popolo, non perirà dalla terra.

Totale (non compresso): 6135 caratteri / byte.

Divertiti!


7
Questa non è una sfida per inventare una lingua, questa è una sfida per comprimere qualcosa.
Giustino,

2
Penso che non includere la dimensione del compilatore / esecutore (compressore / decompressore) nel punteggio renda questa sfida un po 'aperta. Ad un certo punto, la linea tra dizionario e hard-coding diventerà molto sottile.
Dennis,

2
Accidenti, e qui stavo già scrivendo private static final String RICK_ROLL_RETURN = "We're no strangers to love...
Graph Theory

1
Non credo che tu abbia affrontato l'osservazione di Dennis.
Peter Taylor

1
@xem Penso che il post possa essere migliorato organizzando le informazioni in sezioni come #Task, #Input, #Output, #Scoring. Penso anche che la dimensione del codice sorgente per il compressore e il decompressore debba essere inclusa nel punteggio. Questo non fa male a niente, ma risolve il problema sottolineato da Dennis.
Rainbolt,

Risposte:


6

Haskell - 5322 punti

Byte di codice: 686

Misura originale : 6147 = 1871+415+234+108+204+145+297+211+1209+1453

Dimensione codificata: 4636 = 1396+233+163+92+153+115+197+164+979+1144

Punto : 686+ 4636

Compressione del conteggio dei caratteri: ~25%

Codice

Ottimizzazioni a parte, questo memorizza i valori tra 0e7f in caratteri unicode come i loro fattori primi.

Non riduce il numero di byte dell'output codificato, riduce solo il numero di caratteri unicode. Ad esempio, prova # 4 contiene 108caratteri e l'uscita codificato, 92. Le loro rispettive dimensioni sono tuttavia 108e 364byte.

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]

Come funziona

  • Codifica

    1. Ogni carattere viene convertito nel suo equivalente numerico, consente di chiamare questo numero n.
    2. nviene poi convertita in una lista dei suoi fattori primi, ps.
      • Accade convenientemente che i numeri da 0 a 127 abbiano 32 fattori primi comuni, escluso 1. Ciò significa che, i fattori, possono essere memorizzati come indici su un minimo di 5 bit.
      • 1 è un caso speciale ed è rappresentato da un elenco vuoto.
    3. Con psla codifica ora può iniziare.
      1. Ogni numero di psviene convertito nel suo indice nell'elenco di 32 fattori univoci (nel codice sopra questo elenco è identificato come a).
      2. (Tieni presente che a questo punto abbiamo a che fare con un elenco di elenchi di indici di fattori primi) Per procedere al passaggio successivo, è psnecessario appiattirli. Per preservare l'integrità dei dati, ogni elenco viene convertito in un altro elenco di due parti
        1. Il primo elemento memorizza la sua lunghezza e se è composto dallo stesso fattore.
          • Esistono al massimo 6 fattori primi per elenco, queste informazioni sono memorizzate sui 3 bit più a destra. Il quinto bit viene utilizzato come flag per indicare se l'elenco è composto da un singolo fattore.
        2. Gli elementi rimanenti sono gli indici stessi o un singolo indice se nell'elenco sono presenti meno di due diversi fattori.
      3. Questi elenchi sono poi concatenati in un unico elenco appiattita, fs.
    4. Gli elementi di fspossono quindi essere impacchettati in caratteri unicode usando lo spostamento dei bit.
  • decodifica

    • Esegui i passaggi di codifica al contrario.
    • Se ti stai chiedendo come si 1adatta a questo, vorrei ricordartelo product [] == 1.

test

L'uso di questa interfaccia per i test sarebbe doloroso, quindi ho usato questa funzione per fornire i risultati di seguito.

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

Campione

L'output della funzione di codifica gper il test n. 4 è questo
"\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"
o se sei un esperto di incomprensibile, questo
𘑥򎑡𡁢𑒁豱󐰢𼝤􈓃𐲂숼𨐢𐨽𘑥𐦅􈐤򏡡𒁃񈰡񐱂𰠱𑃥􈑃򑑁򔓂踾𑃱󐰢񀰡񔢣𐣃𐲂𓂡􈒑󈡩𠐣𘰢𼝤􈓂숼𨐢𐡁򑐡衣𐢢쑡𡁡𙘽򉡁𙐡􉉅𘑇򎱢𑑡𒂡衂򎑂񤝃𐣃𐲄􈱤􈓃􊡡𙑃񌟂숼𨐡𐱡𡈽𑃢쑁򔓂豁򔢥􈑃𑃢쑢𑡡ꡃ񈰢񄟅􈐤𐦃貱󩐡𐡑󠠰𘡤𠐡𴝣裱󑀡𘱢𑑡𡈹

Note aggiuntive

  • Utilizzando http://mothereff.in/byte-counter , elenchi di directory eedTest le dimensioni dei test sono tutti coerenti ma differiscono ancora dalle dimensioni indicate nella domanda.
  • Il test n. 10 contiene un paio di EM DASH ( ) che ho sostituito -dal momento che sono al di fuori dell'intervallo 0- 7f.
  • È possibile ottenere un'ulteriore compressione utilizzando il quarto bit rimanente durante l'appiattimento, ad esempio il 00caso base, 01ripetere tutto, 10ripetere tranne l'ultimo, 11ripetere tranne gli ultimi due.
  • I file di test e il codice sono tutti disponibili qui https://github.com/gxtaillon/codegolf/tree/master/Kolmogorov

Ciao, grazie per questa risposta! :) Non ho capito che cosa accade in binario quando si converte abcdefghijklm...a 𘑥򎑡𡁢𑒁豱󐰢𼝤..., potrebbe spiegare un po 'di più per favore? Inoltre, ho corretto i conteggi dei caratteri e convertito i trattini in # 10, nella domanda. Il mio conteggio dei caratteri è comunque diverso dal tuo, comunque. Non so perché, ho usato lo strumento mothereff.in.
XX

@xem I dettagli intricati sono stati rivelati.
gxtaillon,

La mia mente è (in senso figurato) letteralmente sconvolta dall'idea che i numeri 0 e 2-127 possano essere codificati su 5 bit. L'hai trovato da solo o era noto? Domanda bonus: quanti bit sono necessari per memorizzare solo i caratteri ASCII stampabili, ovvero 95 caratteri diversi?
XX

@xem I numeri non sono codificati su 5 bit, ciascuno dei loro fattori lo sono. Sarei molto felice se avessi trovato un modo per codificare 7 bit su solo 5. Per quanto riguarda i caratteri ASCII, usando questo metodo avrebbero comunque bisogno di 5 bit ciascuno.
gxtaillon,

1
Poiché nell'intervallo specificato sono presenti al massimo 6 fattori per numero, la lunghezza utilizza 3 "blocchi" di 5 bit. Quindi gli indici vengono codificati su 5 bit, sì. In questa implementazione, uno dei 2 bit non utilizzati nel blocco di lunghezza viene utilizzato per ottenere una compressione aggiuntiva.
gxtaillon,

4

C ++ (C ++ 11), 2741 punti

Questa risposta utilizza UTF-32 come codifica per il testo compresso.

#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();}

Conteggi e punteggio

Codice: 593 caratteri (la nuova riga finale viene rimossa)

Testi compressi (caratteri unicode) : 654 + 145 + 82 + 38 + 51 + 104 + 73 + 423 + 506 = 2148 (contati wc -mper il numero di caratteri unicode anziché byte, i conteggi dei byte sono, come nella risposta di @ gxtaillon , superiore agli originali, 8413 byte in totale, come contato con wc -c).

Rapporto di compressione (da ASCII a unicode) : 35,01% (utilizzando i 6135 byte della domanda (uguale a wc -c))

Attenzione:

Molte shell non sono in grado di gestire i caratteri Unicode prodotti da questo programma. Pertanto, la decompressione può portare al taglio del testo da qualche parte quando la shell non è in grado di gestire un carattere, poiché l'input viene preso stdindalla shell.

compilazione

Dovrebbe compilare con clang++e g++ -std=c++11, ma mostrerà alcuni avvertimenti sulla precedenza dell'operatore, poiché un'espressione simile b<<20-n&0xFFFFFnon verrà trattata come ((b << 20) - n) & 0xFFFFF, come ci si potrebbe aspettare, ma piuttosto come(b << (20 - n)) & 0xFFFFF .

uso

  • Compilare il programma in un eseguibile, ad es ./compress .
  • Esegui il programma ./compress cper comprimere o ./compress ddecomprimere. (Attento, tralasciando l'opzione si ottiene un SEGFAULT (il controllo degli errori è così costoso per il personaggio ...) e altre opzioni (come usare Dinvece did ) possono dare risultati inaspettati
  • L'input viene letto stdine l'output scritto instdout

Come funziona

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();
}

Spiegazione

Poiché sono consentiti tutti i caratteri Unicode da U+0000a U+10FFFF, possiamo usare 20 bit per carattere Unicode:U+FFFFF usa 20 bit ed è ancora incluso nell'intervallo consentito. Quindi, proviamo solo a stipare tutti i singoli bit di caratteri ASCII nei caratteri unicode per memorizzare più caratteri ASCII in un carattere unicode. Tuttavia, dobbiamo anche memorizzare il numero di bit utilizzati nell'ultimo carattere unicode, poiché i bit di immondizia inutilizzati potrebbero altrimenti essere interpretati come caratteri ASCII compressi appropriati. Poiché il numero massimo di bit utilizzati nell'ultimo carattere Unicode è 20, avremo bisogno di 5 bit per quello, che sono posizionati all'inizio dei dati compressi.

Esempio di output

Questo è l'output per esempio n. 4 (come indicato da 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>

( 쏏𦛏dare <U+C3CF><U+266CF>come codici carattere, ma potrei essermi sbagliato)


2

Python 3, 289 + 818 = 1107 punti

Solo leggermente golf.

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'))

La dimensione totale del codice è di 289 byte e codifica i 6135 byte dati in 818 caratteri Unicode - il conteggio totale dei byte di output è di 3201 byte, significativamente inferiore rispetto agli input originali.

Codifica usando zlib, quindi secondariamente usando la codifica Unicode. Era necessaria una logica in più per evitare i surrogati (che Python odia davvero).

Esempio di output da # 4, visto da less(37 caratteri Unicode):

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>

Programma driver per test:

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)

Conteggio byte di output:

 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

1
Il fatto che questo stia utilizzando una libreria di compressione non è un po 'imbrogliante?
Decadimento beta

@BetaDecay: non si limita a questo nella domanda, quindi ho pensato che fosse un gioco giusto.
nneonneo,

Inoltre, è necessario includere un decompressore.
Decadimento beta del

@BetaDecay: pè il packer, uè il packer.
nneonneo,

1

Python 2 - 1141 punti

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)

La dimensione del codice è di 281byte e codifica i 6135byte in 860caratteri unicode.

Come funziona:

Per codificare:

  1. Comprime la stringa da codificare.
  2. Interpreta la stringa compressa come un numero 256 di base.
  3. Converti il ​​numero in binario.
  4. Dividi il binario in gruppi di 19bit, aggiungi un 1po 'all'inizio di ciascuno di essi, quindi converti in caratteri Unicode.

La decodifica è il contrario.

Nota che alcune versioni di Python possono gestire solo caratteri unicode fino a 0xFFFF, e quindi questo codice genererà a ValueError.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.