Siapa yang ingin menjadi pemenang kompleksitas Kolmogorov?

22

Misi Anda hari ini adalah menciptakan kompresor teks.

Tugas

Anda akan menulis dua fungsi:

  • The packer adalah fungsi yang menerima sebuah string karakter ASCII (U + 0000 untuk U + 007F) dan output string Unicode (U + 0000 untuk U + 10FFFF), yang berisi karakter yang mungkin paling sedikit.

  • The unpacker adalah fungsi yang menerima sebuah Unicode string disandikan dan output persis ASCII string asli.

Memasukkan

Satu-satunya input yang diotorisasi adalah string ASCII (untuk pengemas) dan string Unicode yang dikemas (untuk pengurai). Tidak ada input pengguna, tidak ada koneksi internet, tidak ada penggunaan sistem file.

Fungsi Anda dapat memiliki akses ke daftar kata-kata bahasa Inggris ini . Anda dapat menggunakan daftar ini sebagai file txt lokal, atau menyalin kontennya dalam kode sumber Anda sebagai string atau array string .

Anda tidak dapat menyalin kode snippet di bawah ini di fungsi Anda.

Keluaran

Satu-satunya keluaran resmi untuk kedua fungsi adalah string.

Output dari unpacker harus mengandung karakter yang persis sama dengan input dari packer.

Input dan output Anda dapat menggunakan pengkodean karakter apa pun yang mendukung semua Unicode (UTF-8/16/32, GB18030, ...), karena skor Anda hanya akan bergantung pada jumlah karakter Unicode dalam output. Harap pastikan pengkodean mana yang Anda gunakan.

Untuk menghitung jumlah karakter Unicode dalam output Anda, Anda dapat menggunakan alat ini: http://mothereff.in/byte-counter

Mencetak gol

Entri Anda harus dapat mengemas dan membongkar 10 cuplikan teks berikut (yang saya ambil di forum ini).

Skor Anda akan menjadi jumlah dari ukuran 10 string Anda (dalam karakter Unicode) + ukuran dua fungsi Anda (dalam karakter Unicode juga)

Jangan hitung ukuran kamus jika Anda menggunakannya.

Harap sertakan di dalam entri Anda "skor" dari setiap cuplikan dan versi dikemasnya.

Skor terendah menang.

Data

Berikut ini cuplikan untuk disandikan untuk menghitung skor Anda:

1: Lirik Rick Roll (1870b): Kami tidak asing dengan kode golf, Anda tahu aturannya, dan saya juga

Kami bukan orang asing untuk dicintai
Anda tahu aturannya dan saya juga
Komitmen penuh adalah apa yang saya pikirkan
Anda tidak akan mendapatkan ini dari pria lain
Aku hanya ingin memberitahumu bagaimana perasaanku
Harus membuatmu mengerti

Tak akan menyerahkanmu
Tidak akan pernah mengecewakan Anda
Tidak akan pernah berlari dan meninggalkanmu
Tidak akan pernah membuatmu menangis
Tidak akan pernah pamit
Tidak akan pernah berbohong dan menyakitimu

Kami sudah saling kenal begitu lama
Hatimu sakit tapi
Kamu terlalu malu untuk mengatakannya
Di dalam kita berdua tahu apa yang sedang terjadi
Kami tahu permainannya dan kami akan memainkannya
Dan jika Anda bertanya bagaimana perasaan saya
Jangan bilang kamu terlalu buta untuk melihat

Tak akan menyerahkanmu
Tidak akan pernah mengecewakan Anda
Tidak akan pernah berlari dan meninggalkanmu
Tidak akan pernah membuatmu menangis
Tidak akan pernah pamit
Tidak akan pernah berbohong dan menyakitimu

Tak akan menyerahkanmu
Tidak akan pernah mengecewakan Anda
Tidak akan pernah berlari dan meninggalkanmu
Tidak akan pernah membuatmu menangis
Tidak akan pernah pamit
Tidak akan pernah berbohong dan menyakitimu

(Ooh, menyerahlah)
(Ooh, menyerahlah)
(Ooh)
Tidak akan pernah memberi, tidak akan pernah memberi
(Menyerah)
(Ooh)
Tidak akan pernah memberi, tidak akan pernah memberi
(Menyerah)

Kami sudah saling kenal begitu lama
Hatimu sakit tapi
Kamu terlalu malu untuk mengatakannya
Di dalam kita berdua tahu apa yang sedang terjadi
Kami tahu permainannya dan kami akan memainkannya

Aku hanya ingin memberitahumu bagaimana perasaanku
Harus membuatmu mengerti

Tak akan menyerahkanmu
Tidak akan pernah mengecewakan Anda
Tidak akan pernah berlari dan meninggalkanmu
Tidak akan pernah membuatmu menangis
Tidak akan pernah pamit
Tidak akan pernah berbohong dan menyakitimu

Tak akan menyerahkanmu
Tidak akan pernah mengecewakan Anda
Tidak akan pernah berlari dan meninggalkanmu
Tidak akan pernah membuatmu menangis
Tidak akan pernah pamit
Tidak akan pernah berbohong dan menyakitimu

Tak akan menyerahkanmu
Tidak akan pernah mengecewakan Anda
Tidak akan pernah berlari dan meninggalkanmu
Tidak akan pernah membuatmu menangis
Tidak akan pernah pamit
Tidak akan pernah berbohong dan menyakitimu

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

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

3: the number diamond (233b): Cetak berlian ini

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

4: alfabet empat kali (107b): Cetak alfabet empat kali

abcdefghijklmnopqrstuvwxyz
qwertyuiopasdfghjklzxcvbnm
pyfgcrlaoeuidhtnsqjkxbmwvz
zyxwvutsrqponmlkjihgfedcba

5: Lirik Old McDonald's (203b): Fungsi Old MacDonald

Old MacDonald memiliki sebuah peternakan, EIEIO,
Dan di peternakan itu dia punya seekor sapi, EIEIO,
Dengan moo moo di sini dan moo moo di sana,
Di sini moo, ada moo, di mana-mana moo moo,
Old MacDonald punya pertanian, EIEIO!

6: Lirik Rock around the clock (144b): Rock Around the Clock

1, 2, 3 jam, 4 jam rock,
Jam 5, 6, 7, jam 8,
Jam 9, 10, 11, jam 12 siang,
Kami akan nge-rock sepanjang waktu malam ini.

7: Hello World (296b): Katakan "Halo" kepada dunia dalam seni ASCII

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

8: Berkat Irlandia (210b): An Old Irish Blessing

Semoga kita menemukan jalan untuk bertemu
Semoga angin selalu ada di belakang Anda
Semoga matahari menyinari wajah Anda
Hujan turun lembut di ladang Anda
Dan sampai kita bertemu lagi
Semoga Tuhan memegang Anda di lekukan tangan-Nya

9: Ada lirik wanita tua (1208b): Ada Wanita Tua

Ada seorang wanita tua yang menelan lalat.  
Saya tidak tahu mengapa dia menelan lalat itu,  
Mungkin dia akan mati.

Ada seorang wanita tua yang menelan laba-laba,  
Itu menggeliat dan bergoyang-goyang dan berguncang di dalam dirinya.  
Dia menelan laba-laba untuk menangkap lalat,  
Saya tidak tahu mengapa dia menelan lalat itu,  
Mungkin dia akan mati.

Ada seorang wanita tua yang menelan seekor burung,  
Betapa absurdnya menelan burung.  
Dia menelan burung itu untuk menangkap laba-laba,  
Dia menelan laba-laba untuk menangkap lalat,  
Saya tidak tahu mengapa dia menelan lalat itu,  
Mungkin dia akan mati.

Ada seorang wanita tua yang menelan seekor kucing,  
Bayangkan itu menelan seekor kucing.  
Dia menelan kucing itu untuk menangkap burung itu,  
Dia menelan burung itu untuk menangkap laba-laba,  
Dia menelan laba-laba untuk menangkap lalat,  
Saya tidak tahu mengapa dia menelan lalat itu,  
Mungkin dia akan mati.

Ada seorang wanita tua yang menelan seekor anjing,  
Betapa babi harus menelan seekor anjing.  
Dia menelan anjing itu untuk menangkap kucing itu,  
Dia menelan kucing itu untuk menangkap burung itu,  
Dia menelan burung itu untuk menangkap laba-laba,  
Dia menelan laba-laba untuk menangkap lalat,  
Saya tidak tahu mengapa dia menelan lalat itu,  
Mungkin dia akan mati.

Ada seorang wanita tua yang menelan seekor kuda,  
Dia meninggal tentu saja.

10: alamat gettysburg (1452b): Seberapa acak Alamat Gettysburg

Empat skor dan tujuh tahun yang lalu ayah kita menghasilkan di benua baru ini sebuah negara baru, diciptakan dalam kebebasan, dan didedikasikan untuk proposisi bahwa semua manusia diciptakan sama. Sekarang kita terlibat dalam perang saudara yang hebat, menguji apakah negara itu, atau negara mana pun yang dikonsep dan begitu berdedikasi, dapat bertahan lama. Kita bertemu di medan perang yang hebat. Kami datang untuk mendedikasikan sebagian dari ladang itu, sebagai tempat peristirahatan terakhir bagi mereka yang di sini memberikan hidup mereka agar bangsa itu bisa hidup. Sangat tepat dan patut kita melakukan ini. Tetapi, dalam arti yang lebih besar, kita tidak bisa mendedikasikan, kita tidak bisa menguduskan, kita tidak bisa menguduskan tanah ini. Orang-orang pemberani, hidup dan mati, yang berjuang di sini, telah menguduskannya, jauh di atas kekuatan buruk kita untuk menambah atau mengurangi. Dunia akan sedikit memperhatikan, atau lama mengingat apa yang kita katakan di sini, tetapi tidak pernah bisa melupakan apa yang mereka lakukan di sini. Bagi kami yang hidup, lebih tepatnya, didedikasikan di sini untuk pekerjaan yang belum selesai yang sejauh ini telah mereka perjuangkan dengan begitu mulia. Adalah lebih baik bagi kita untuk berada di sini didedikasikan untuk tugas besar yang tersisa di hadapan kita - bahwa dari orang-orang mati yang terhormat kita semakin meningkatkan pengabdian kepada sebab yang mereka berikan ukuran penuh terakhir dari pengabdian - bahwa kita di sini sangat memutuskan bahwa orang-orang mati ini tidak akan telah mati sia-sia - bahwa bangsa ini, di bawah Tuhan, akan memiliki kelahiran baru yang bebas - dan bahwa pemerintahan rakyat, oleh rakyat, untuk rakyat, tidak akan binasa dari bumi.

Total (tidak terkompresi): 6135 karakter / byte.

Selamat bersenang-senang!

xem
sumber
7
Ini bukan tantangan untuk menciptakan bahasa, ini adalah tantangan untuk mengompres sesuatu.
Justin
2
Saya pikir tidak termasuk ukuran kompiler / pelaksana (kompresor / dekompresor) dalam skor membuat tantangan ini sedikit terbuka. Pada titik tertentu, garis antara kamus dan hard-coding akan menjadi sangat tipis.
Dennis
2
Sial, dan di sini saya sudah mengetik private static final String RICK_ROLL_RETURN = "We're no strangers to love...
Graph Theory
1
Saya tidak berpikir Anda sudah membahas pengamatan Dennis.
Peter Taylor
1
@ xem Saya pikir posting dapat ditingkatkan dengan mengatur informasi menjadi beberapa bagian seperti #Task, #Input, #Output, #Scoring. Saya juga berpikir bahwa ukuran kode sumber untuk kompresor dan dekompresor harus dimasukkan dalam skor. Ini tidak sakit apa-apa, tapi itu memecahkan masalah yang ditunjukkan Dennis.
Rainbolt

Jawaban:

6

Haskell - 5322 poin

Byte kode: 686

Ukuran asli : 6147 = 1871+415+234+108+204+145+297+211+1209+1453

Ukuran yang dikodekan: 4636 = 1396+233+163+92+153+115+197+164+979+1144

Skor: 686+ 4636

Kompresi jumlah karakter: ~25%

Kode

Selain optimasi, ini menyimpan nilai antara 0dan7f dalam karakter unicode sebagai faktor utama mereka.

Itu tidak menurunkan jumlah byte dari output yang disandikan, itu hanya menurunkan jumlah karakter unicode. Misalnya, uji # 4 berisi 108karakter dan output yang disandikan 92,. Namun ukuran masing-masing 108dan 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]

Bagaimana itu bekerja

  • Pengkodean

    1. Setiap karakter dikonversi ke angka yang setara, mari kita panggil nomor ini n.
    2. nkemudian dikonversi menjadi daftar faktor utamanya ps,.
      • Kebetulan angka 0 hingga 127 memiliki 32 faktor prima yang sama, tidak termasuk 1. Ini berarti mereka, faktor-faktornya, dapat disimpan sebagai indeks hanya dengan 5 bit.
      • 1 adalah kasus khusus dan diwakili oleh daftar kosong.
    3. Dengan psencoding sekarang dapat mulai.
      1. Setiap jumlah psdikonversi menjadi indeks dalam daftar 32 faktor unik (Dalam kode di atas daftar ini diidentifikasi sebagai a).
      2. (Perlu diingat pada titik ini kita berhadapan dengan daftar daftar indeks faktor prima). Untuk melanjutkan ke langkah berikutnya, psperlu diratakan. Untuk menjaga integritas data, setiap daftar diubah menjadi daftar dua bagian lainnya
        1. Elemen pertama menyimpan panjangnya dan jika itu terdiri dari faktor yang sama.
          • Paling banyak ada 6 faktor utama per daftar, informasi ini disimpan pada 3 bit paling kanan. Bit kelima digunakan sebagai bendera untuk menunjukkan apakah daftar terdiri dari satu faktor.
        2. Elemen yang tersisa adalah indeks itu sendiri atau indeks tunggal jika ada kurang dari dua faktor yang berbeda dalam daftar.
      3. Daftar ini kemudian digabung menjadi satu daftar datar fs,.
    4. Elemen-elemen dari fskemudian dapat dikemas ke dalam karakter unicode menggunakan bit shifting.
  • Decoding

    • Lakukan langkah-langkah penyandian secara terbalik.
    • Jika Anda bertanya-tanya seberapa 1cocok ini, saya ingin mengingatkan Anda tentang itu product [] == 1.

Tes

Menggunakan antarmuka ini untuk pengujian akan menyakitkan, jadi saya menggunakan fungsi ini untuk memberikan hasil di bawah ini.

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

Mencicipi

Output dari fungsi encoding guntuk test # 4 adalah ini
"\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"
atau jika Anda mahir omong kosong, ini
𘑥򎑡𡁢𑒁豱󐰢𼝤􈓃𐲂숼𨐢𐨽𘑥𐦅􈐤򏡡𒁃񈰡񐱂𰠱𑃥􈑃򑑁򔓂踾𑃱󐰢񀰡񔢣𐣃𐲂𓂡􈒑󈡩𠐣𘰢𼝤􈓂숼𨐢𐡁򑐡衣𐢢쑡𡁡𙘽򉡁𙐡􉉅𘑇򎱢𑑡𒂡衂򎑂񤝃𐣃𐲄􈱤􈓃􊡡𙑃񌟂숼𨐡𐱡𡈽𑃢쑁򔓂豁򔢥􈑃𑃢쑢𑡡ꡃ񈰢񄟅􈐤𐦃貱󩐡𐡑󠠰𘡤𠐡𴝣裱󑀡𘱢𑑡𡈹

Catatan tambahan

  • Menggunakan http://mothereff.in/byte-counter , daftar direktori danedTest ukuran tes semuanya konsisten tetapi masih berbeda dari ukuran yang ditunjukkan dalam pertanyaan.
  • Uji # 10 mengandung beberapa strip EM ( ) bahwa saya diganti dengan -karena mereka berada di luar 0- 7fjangkauan.
  • Kompresi lebih lanjut dapat dicapai dengan menggunakan bit keempat yang tersisa sambil meratakan, misalnya, 00casing dasar, 01ulangi semua, 10ulangi kecuali yang terakhir, 11ulangi kecuali dua yang terakhir.
  • File pengujian dan kode semuanya tersedia di sini https://github.com/gxtaillon/codegolf/tree/master/Kolmogorov
gxtaillon
sumber
Halo, terima kasih atas jawaban ini! :) Saya tidak mengerti apa yang terjadi dalam biner ketika Anda mengkonversi abcdefghijklm...ke 𘑥򎑡𡁢𑒁豱󐰢𼝤..., bisa Anda jelaskan sedikit lebih lanjut silahkan? Juga, saya telah memperbaiki jumlah char dan mengonversikan em-dash di # 10, dalam pertanyaan. Jumlah char saya masih berbeda dari milik Anda. Entah mengapa, saya menggunakan alat mothereff.in.
xem
@xem Detail rumit telah terungkap.
gxtaillon
Pikiranku (secara kiasan) benar-benar hancur oleh gagasan bahwa angka 0 dan 2-127 dapat dikodekan pada 5 bit. Apakah Anda menemukan ini sendiri atau itu sesuatu yang diketahui? Pertanyaan bonus: berapa banyak bit yang Anda perlukan untuk hanya menyimpan karakter ascii yang dapat dicetak, yaitu 95 karakter yang berbeda?
xem
@xem Angka-angka tidak dikodekan pada 5 bit, masing-masing faktornya. Saya akan sangat senang jika saya telah menemukan cara pengkodean 7 bit hanya pada 5. Sedangkan untuk karakter ascii, menggunakan metode ini mereka masih akan membutuhkan 5 bit masing-masing.
gxtaillon
1
Karena dalam rentang yang Anda tentukan ada paling banyak 6 faktor per angka, panjangnya menggunakan 3 dari 5 bit "blok". Kemudian indeks dikodekan pada 5 bit, ya. Dalam implementasi ini, salah satu dari 2 bit yang tidak digunakan dalam blok panjang digunakan untuk mendapatkan kompresi tambahan.
gxtaillon
4

C ++ (C ++ 11), 2741 poin

Jawaban ini menggunakan UTF-32 sebagai pengodean untuk teks yang dikompresi.

#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 menghitung dan mencetak gol

Kode: 593 karakter (baris baru tertinggal dilepaskan)

Teks terkompresi (karakter unicode) : 654 + 145 + 82 + 38 + 51 + 104 + 73 + 423 + 506 = 2148 (dihitung denganwc -m jumlah karakter unicode daripada byte, jumlah byte adalah, seperti halnya dengan jawaban @ gxtaillon , lebih tinggi dari aslinya, 8413 byte total, sebagaimana dihitung dengan wc -c).

Rasio kompresi (ASCII ke unicode) : 35,01% (menggunakan 6135 byte dari pertanyaan (sama sepertiwc -c ))

Waspadalah:

Banyak shell tidak dapat menangani karakter unicode yang dihasilkan oleh program ini. Dengan demikian, dekompresi dapat menyebabkan teks terputus di suatu tempat ketika shell tidak dapat menangani karakter, karena input diambil melaluistdin dari shell.

Kompilasi

Ini harus dikompilasi dengan clang++ dan g++ -std=c++11, tetapi akan menampilkan beberapa peringatan tentang prioritas operator, karena ekspresi seperti b<<20-n&0xFFFFFtidak akan diperlakukan sebagai ((b << 20) - n) & 0xFFFFF, seperti yang diharapkan, tetapi sebagai(b << (20 - n)) & 0xFFFFF .

Pemakaian

  • Kompilasi program menjadi executable, mis ./compress .
  • Jalankan program ./compress cuntuk kompres atau ./compress ddekompresi. (Hati-hati, meninggalkan opsi memberi SEGFAULT (pengecekan kesalahan sangat mahal ...) dan opsi lainnya (seperti menggunakan Dalih-alih menggunakand ) dapat memberikan hasil yang tidak terduga
  • Input dibaca dari stdin dan output ditulis kestdout

Bagaimana itu bekerja

Tidak disatukan

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

Penjelasan

Karena semua karakter unicode dari U+0000hingga U+10FFFFdiizinkan, kami dapat menggunakan 20 bit per karakter unicode:U+FFFFF menggunakan 20 bit dan masih termasuk dalam rentang yang diizinkan. Jadi, kami hanya mencoba menjejalkan semua bit karakter ASCII individu ke dalam karakter unicode untuk menyimpan beberapa karakter ASCII dalam satu karakter unicode. Namun, kita juga perlu menyimpan jumlah bit yang digunakan dalam karakter unicode terakhir, karena bit sampah yang tidak digunakan dapat ditafsirkan sebagai karakter ASCII terkompresi yang tepat. Karena jumlah maksimum bit yang digunakan dalam karakter unicode terakhir adalah 20, kita akan membutuhkan 5 bit untuk itu, yang ditempatkan di awal data terkompresi.

Contoh output

Ini adalah output misalnya # 4 (seperti yang diberikan oleh 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>

( 쏏𦛏berikan <U+C3CF><U+266CF>sebagai kode karakter, tapi saya mungkin salah)

hlt
sumber
2

Python 3, 289 + 818 = 1107 poin

Hanya golf ringan.

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

Ukuran kode total adalah 289 byte, dan mengkodekan 6135 byte yang diberikan ke 818 karakter Unicode - jumlah total output byte adalah 3201 byte, jauh lebih kecil dari input asli.

Mengkodekan menggunakan zlib, kemudian menggunakan pengkodean unicode. Beberapa logika tambahan diperlukan untuk menghindari pengganti (yang Python benar-benar benci).

Contoh output dari # 4, seperti yang terlihat oleh less(37 karakter 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>

Program driver untuk pengujian:

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)

Hitungan byte keluaran:

 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
sumber
1
Bukankah fakta bahwa ini menggunakan perpustakaan kompresi sedikit curang?
Beta Decay
@ BetaDecay: Itu tidak membatasi itu dalam pertanyaan, jadi saya pikir itu adalah permainan yang adil.
nneonneo
Juga, Anda perlu menyertakan dekompresor.
Beta Decay
@ BetaDecay: padalah pembungkusnya, uadalah pembongkar bungkusnya .
nneonneo
1

Python 2 - 1141 poin

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)

Ukuran kode adalah 281byte dan mengkodekan 6135byte ke860 karakter unicode.

Bagaimana itu bekerja:

Untuk Menyandikan:

  1. Kompres string yang akan dikodekan.
  2. Menafsirkan string yang dikompresi sebagai angka 256 basis.
  3. Ubah nomornya menjadi biner.
  4. Membagi biner menjadi kelompok-kelompok 19bit, tambahkan 1sedikit ke awal masing-masing, dan kemudian dikonversi ke karakter Unicode.

Decoding adalah kebalikannya.

Perhatikan bahwa beberapa versi python hanya dapat menangani karakter unicode hingga 0xFFFF, dan dengan demikian kode ini akan menaikkan a ValueError.

pppery
sumber