誰がコルモゴロフの複雑さの勝者になりたいですか?


22

今日の使命は、テキストコンプレッサーを発明することです。

仕事

次の2つの関数を作成します。

  • パッカーは、 ASCII文字(U + 007FにU + 0000)の文字列を受け取り、可能な最も少ない文字を含む、Unicode文字列(U + 10FFFFにU + 0000)を出力する機能です。

  • アンパッカーは、エンコードされたUnicode文字列を受け取り、正確に元のASCII文字列を出力する関数です。

入力

許可される入力は、ASCII文字列(パッカー用)とパックされたUnicode文字列(アンパッカー用)のみです。ユーザー入力なし、インターネット接続なし、ファイルシステムの使用なし。

あなたの関数はこの英語の単語のリストにアクセスできます。このリストをローカルのtxtファイルとして使用するか、ソースコードのコンテンツを文字列または文字列の配列としてコピーできます

以下のスニペットを関数にハードコーディングすることはできません。

出力

両方の関数の唯一の許可された出力は文字列です。

アンパッカーの出力には、パッカーの入力とまったく同じ文字が含まれている必要があります。

入力と出力は、すべてのUnicode(UTF-8 / 16/32、GB18030、...)をサポートする任意の文字エンコードを使用できます。スコアは出力内のUnicode文字の数にのみ依存するためです。ただし、使用しているエンコードを正確に指定してください。

出力内のUnicode文字の数をカウントするには、次のツールを使用できます。http//mothereff.in/byte-counter

得点

エントリは、次の10個のテキストスニペット(このフォーラムで取り上げたもの)をパックおよびアンパックできる必要があります。

スコアは、10個のパックされた文字列のサイズ(Unicode文字)+ 2つの関数のサイズ(Unicode文字)の合計になります

辞書を使用する場合は、辞書のサイズをカウントしないでください。

エントリには、各スニペットの「スコア」とパックバージョンを含めてください。

最低スコアが勝ちます。

データ

スコアを計算するためにエンコードするスニペットは次のとおりです。

1:Rick Rollの歌詞(1870b):ゴルフをコーディングするのは見知らぬ人ではありません。ルールを知っているので、私もそうです。

私たちは愛する見知らぬ人ではありません
あなたはルールを知っているので、私もそうです
完全なコミットメントが私が考えていることです
他の男からこれを取得することはありません
私の気持ちを伝えたいだけです
理解させる

あなたをあきらめるつもりはありません
失望させない
走り回ってあなたを捨てない
泣かないで
さよならを言うつもりはない
嘘をついて傷つけない

私たちは長い間お互いを知っていました
あなたの心は痛むが
あなたはそれを言うにはあまりにも恥ずかしがり屋です
内部で私たちは何が起こっているかを知っています
私たちはゲームを知っていて、それをプレイするつもりです
そして、あなたが私にどのように感じているかを尋ねると
盲目だから見えないって言わないで

あなたをあきらめるつもりはありません
失望させない
走り回ってあなたを捨てない
泣かないで
さよならを言うつもりはない
嘘をついて傷つけない

あなたをあきらめるつもりはありません
失望させない
走り回ってあなたを捨てない
泣かないで
さよならを言うつもりはない
嘘をついて傷つけない

(ああ、あきらめます)
(ああ、あきらめます)
(ああ)
与えない、与えない
(あきらめて)
(ああ)
与えない、与えない
(あきらめて)

私たちは長い間お互いを知っています
あなたの心は痛むが
あなたはそれを言うにはあまりにも恥ずかしがり屋です
内部で私たちは何が起こっているかを知っています
私たちはゲームを知っていて、それをプレイするつもりです

私の気持ちを伝えたいだけです
理解させる

あなたをあきらめるつもりはありません
失望させない
走り回ってあなたを捨てない
泣かないで
さよならを言うつもりはない
嘘をついて傷つけない

あなたをあきらめるつもりはありません
失望させない
走り回ってあなたを捨てない
泣かないで
さよならを言うつもりはない
嘘をついて傷つけない

あなたをあきらめるつもりはありません
失望させない
走り回ってあなたを捨てない
泣かないで
さよならを言うつもりはない
嘘をついて傷つけない

2:The Golfer(412b):アスキーアートのゴルフ

      '\。。|> 18 >>
        \ 」|
       O >>。'o |
        \ |
        / \。|
       / /。 ' |
 jgs ^^^^^^^ `^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^

3:数字のダイヤモンド(233b):このダイヤモンドを印刷

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

4:アルファベット4回(107b):アルファベット4回印刷

abcdefghijklmnopqrstuvwxyz
qwertyuiopasdfghjklzxcvbnm
pyfgcrlaoeuidhtnsqjkxbmwvz
zyxwvutsrqponmlkjihgfedcba

5:オールドマクドナルドの歌詞(203b):オールドマクドナルド関数

オールドマクドナルドにはEEIIOという農場があり、
そして、その農場で彼は牛、EIEIO、
ここにmoo mooがあり、そこにmoo mooがあります。
ここでmoo、そこにmoo、どこにでもmoo moo、
古いマクドナルドには、EIEIOの農場がありました!

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

1、2、3時、4時のロック、
5、6、7時、8時ロック、
9、10、11時、12時のロック、
今夜は24時間ロックします。

7:Hello World(296b):ASCIIアートで世界に「こんにちは」と言う

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

8:アイルランドの祝福(210b):古いアイルランドの祝福

道があなたに会うために立ち上がりますように
追い風が常に吹いていますように
太陽があなたの顔を暖かく照らしますように
雨が畑に降りそそぐ
そしてまた会うまで
神があなたを彼の手のくぼみに抱いてくださいますように

9:老婦人の歌詞がありました(1208b):老婦人がいました

ハエを飲み込んだ老婦人がいました。  
彼女がそのハエを飲み込んだ理由はわかりませんが、  
おそらく彼女は死ぬでしょう。

クモを飲み込んだ老婦人がいました  
それは彼女のなかでくすくすと揺れ動き、揺れた。  
彼女はハエを捕まえるためにクモを飲み込んだ、  
彼女がそのハエを飲み込んだ理由はわかりませんが、  
おそらく彼女は死ぬでしょう。

鳥を飲み込んだ老婦人がいました  
鳥を飲み込むなんて馬鹿げている。  
彼女は鳥を飲み込んでクモを捕まえ、  
彼女はハエを捕まえるためにクモを飲み込んだ、  
彼女がそのハエを飲み込んだ理由はわかりませんが、  
おそらく彼女は死ぬでしょう。

猫を飲み込んだ老婦人がいました  
猫を飲み込むと想像してください。  
彼女は鳥を捕まえるために猫を飲み込んだ、  
彼女は鳥を飲み込んでクモを捕まえ、  
彼女はハエを捕まえるためにクモを飲み込んだ、  
彼女がそのハエを飲み込んだ理由はわかりませんが、  
おそらく彼女は死ぬでしょう。

犬を飲み込んだ老婦人がいました  
犬を飲み込むのはなんと豚。  
彼女は猫を捕まえるために犬を飲み込んだ、  
彼女は鳥を捕まえるために猫を飲み込んだ、  
彼女は鳥を飲み込んでクモを捕まえ、  
彼女はハエを捕まえるためにクモを飲み込んだ、  
彼女がそのハエを飲み込んだ理由はわかりませんが、  
おそらく彼女は死ぬでしょう。

馬を飲み込んだ老婦人がいました  
彼女はもちろん亡くなりました。

10:ゲティスバーグの住所(1452b):ゲティスバーグの住所はどのくらいランダムですか

4スコアと7年前、私たちの父親はこの大陸に新しい国を生み出し、自由に考え、すべての人が平等に創造されるという命題に捧げました。現在、私たちは大規模な内戦に取り組んでおり、その国、またはそのように考えられ、献身的な国が長く耐えられるかどうかをテストしています。私たちはその戦争の大きな戦場で出会います。ここで、その国が生きるために命を捧げた人々のための最終的な休憩場所として、その分野の一部を捧げるようになりました。これを行うのは、完全に適切で適切です。しかし、より広い意味で、私たちは献身することも、奉献することも、この地を神聖にすることもできません。ここで苦労した勇敢な人たちは、生きているか死んでいるかによって、それを奉献してきました。世界はここで私たちが言ったことをほとんど気づかず、長く覚えません。しかし、彼らがここでやったことを決して忘れることはできません。むしろ、ここで戦った彼らがこれまでに気高い進歩を遂げた未完成の仕事にここで捧げることは、私たちにとって生きていることです。むしろ、ここで私たちが私たちの前に残っている偉大な仕事に専念することです-これらの名誉ある死から、私たちは彼らが最後の献身の完全な手段を与えた原因に献身します-私たちはここでこれらの死者が神の下でこの国が新たな自由の誕生を遂げ、人々によって、人々のために、人々のために、地球から滅びることがないように、無駄に死にました。

合計(非圧縮):6135文字/バイト。

楽しむ!


7
これは言語を発明するための挑戦ではなく、これは何かを圧縮するための挑戦です。
ジャスティン14

2
コンパイラー/エグゼキューター(コンプレッサー/デコンプレッサー)のサイズをスコアに含めないことで、この課題は少し無制限になります。ある時点で、辞書ハードコーディングの間の線は非常に薄くなります。
デニス14

2
くそー、そしてここで私はすでに入力していた private static final String RICK_ROLL_RETURN = "We're no strangers to love...
グラフ理論14

1
デニスの観察に取り組んだとは思わない。
ピーターテイラー14

1
@xem投稿は、#Task、#Input、#Output、#Scoringなどのセクションに情報を整理することで改善できると思います。また、コンプレッサーとデコンプレッサーのソースコードのサイズをスコアに含める必要があると思います。これは何も害はありませんが、デニスが指摘した問題を解決します。
レインボルト14

回答:


6

ハスケル-5322ポイント

コードのバイト: 686

オリジナルサイズ : 6147 = 1871+415+234+108+204+145+297+211+1209+1453

エンコードされたサイズ: 4636 = 1396+233+163+92+153+115+197+164+979+1144

スコア : 686+ 4636

文字数の圧縮: ~25%

コード

脇の最適化、間にこの値を格納する0と、7fその素因数などのUnicode文字インチ

エンコードされた出力のバイト数を減らすことはなく、Unicode文字の数を減らすだけです。たとえば、テスト#4には108文字とエンコードされた出力が含まれます92。ただし108、それぞれのサイズは364バイトです。

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]

使い方

  • エンコーディング

    1. 各文字はそれに相当する数値に変換されますn。この番号を呼び出してください。
    2. n次に、その素因数のリストに変換されpsます。
      • 0〜127の数値には、を除く32の共通素数があることが便利1です。つまり、これらの要素は、わずか5ビットのインデックスとして保存できます。
      • 1 は特別なケースであり、空のリストで表されます。
    3. これpsでエンコードを開始できます。
      1. の各数はps、32個の一意の要素のリスト内のインデックスに変換されます(上記のコードでは、このリストはとして識別されますa)。
      2. (この時点で、素因数のインデックスのリストのリストを扱っていることに留意してください)次のステップに進むには、psフラット化する必要があります。データの整合性を維持するために、各リストは2つの部分からなる別のリストに変換されます
        1. 最初の要素はその長さを格納し、同じ要素で構成されている場合。
          • リストごとに最大6つの素因数があり、この情報は右端の3ビットに格納されます。5番目のビットは、リストが単一の要素で構成されているかどうかを示すフラグとして使用されます。
        2. 残りの要素は、インデックス自体、またはリストに含まれる要素が2つ未満の場合は単一のインデックスです。
      3. これらのリストは、単一のフラット化されたリストに連結されますfs
    4. の要素は、fsビットシフトを使用してUnicode文字にパックできます。
  • デコード

    • エンコード手順を逆に実行します。
    • これにどのように1適合するか疑問に思っているなら、私はあなたにそれを思い出したいと思いますproduct [] == 1

テスト

このインターフェイスをテストに使用するのは苦痛なので、この関数を使用して以下の結果を提供しました。

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

サンプル

gテスト#4のエンコード関数の出力はこれです。
"\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"
または、もしあなたがちらほらの熟練者なら、これは
𘑥򎑡𡁢𑒁豱󐰢𼝤􈓃𐲂숼𨐢𐨽𘑥𐦅􈐤򏡡𒁃񈰡񐱂𰠱𑃥􈑃򑑁򔓂踾𑃱󐰢񀰡񔢣𐣃𐲂𓂡􈒑󈡩𠐣𘰢𼝤􈓂숼𨐢𐡁򑐡衣𐢢쑡𡁡𙘽򉡁𙐡􉉅𘑇򎱢𑑡𒂡衂򎑂񤝃𐣃𐲄􈱤􈓃􊡡𙑃񌟂숼𨐡𐱡𡈽𑃢쑁򔓂豁򔢥􈑃𑃢쑢𑡡ꡃ񈰢񄟅􈐤𐦃貱󩐡𐡑󠠰𘡤𠐡𴝣裱󑀡𘱢𑑡𡈹

追加メモ

  • http://mothereff.in/byte-counterを使用すると、ディレクトリリストとedTestテストのサイズはすべて一貫していますが、質問で示されているサイズとは異なります。
  • テスト#10は、EMダッシュのカップル(含まれている私はと置き換えること)-彼らは外であるため、0- 7f範囲を。
  • 残りの4番目のビットを使用して、たとえば00ベースケース、01すべてを10繰り返す、最後11を除く繰り返し、最後の2つを除く繰り返しなど、さらに圧縮することができます。
  • テストファイルとコードはすべてhttps://github.com/gxtaillon/codegolf/tree/master/Kolmogorovから入手できます

こんにちは、この答えをありがとう!:)に変換abcdefghijklm...したときにバイナリで何が起こるか理解𘑥򎑡𡁢𑒁豱󐰢𼝤...できませんでしたが、もう少し説明してください。また、質問の#10で文字カウントを修正し、emダッシュを変換しました。私の文字数はまだあなたのものとは異なります。Dunnoなぜ、mothereff.inツールを使用しました。
xem 14

@xem 複雑な詳細が明らかになりました。
gxtaillon 14

私の心は、数字の0と2-127を5ビットでエンコードできるという考えに(形容的に)文字通り吹き飛ばされます。自分でこれを見つけましたか、それとも何か知られていましたか?おまけの質問:印刷可能なASCII文字、つまり95種類の文字だけを保存するには何ビット必要ですか?
xem 14

@xem数値は5ビットでエンコードされず、それぞれの要因がエンコードされます。5ビットのみで7ビットをエンコードする方法を見つけたら、私は非常にうれしいです。ASCII文字については、この方法を使用する場合、それぞれ5ビットが必要です。
gxtaillon 14

1
指定した範囲では、数値ごとに最大6つのファクターがあるため、長さは5ビットの「ブロック」のうち3つを使用します。次に、インデックスは5ビットでエンコードされます、はい。この実装では、長さブロックの2つの未使用ビットの1つを使用して、追加の圧縮を取得します。
gxtaillon 14

4

C ++(C ++ 11)、2741ポイント

この回答では、圧縮テキストのエンコーディングとしてUTF-32を使用しています。

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

文字数とスコアリング

コード:593文字(末尾の改行は削除されます)

圧縮テキスト(ユニコード文字):654 + 145 + 82 + 38 + 51 + 104 + 73 + 423 + 506 = 2148wc -mバイトではなくユニコード文字の数でカウントされます。バイトカウントは、@ gxtaillonの回答と同様です) 、オリジナルよりも大きい、合計で8413バイト、でカウントwc -c)。

圧縮率(ASCIIからUnicodeへ):35.01%(質問の6135バイトを使用(と同じwc -c))

注意してください:

多くのシェルは、このプログラムが生成するユニコード文字を処理できません。したがって、stdinシェルから入力が行われるため、シェルが文字を処理できない場合、圧縮解除によってテキストがどこかで途切れることがあります。

コンパイル中

それはしてコンパイルする必要があるclang++g++ -std=c++11、それはのような式として、演算子の優先順位についてのいくつかの警告が表示されますb<<20-n&0xFFFFFとして扱われることはありません((b << 20) - n) & 0xFFFFF、むしろとして1想像のとおり、しかし(b << (20 - n)) & 0xFFFFF

使用法

  • プログラムを実行可能ファイルにコンパイルし./compressます。
  • ./compress c圧縮または./compress d解凍するためにプログラムを実行します。(注意、オプションを省略すると、SEGFAULT(エラーチェックは文字の負荷が非常に高くなります...)およびその他のオプション(D代わりにd)は予期しない結果をもたらす可能性があります
  • 入力が読み取られstdin、出力が書き込まれますstdout

使い方

非ゴルフ

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

説明

からU+0000までのすべてのUnicode文字U+10FFFFが許可されているため、Unicode文字ごとに20ビットを使用できます。U+FFFFFビットを使用し、許可範囲に含まれています。したがって、複数のASCII文字を1つのUnicode文字に格納するために、個々のASCII文字ビットをすべてUnicode文字に詰め込むだけです。ただし、未使用のガベージビットは適切な圧縮ASCII文字として解釈される可能性があるため、最後のUnicode文字で使用されているビット数も保存する必要があります。最後のユニコード文字で使用されるビットの最大数は20であるため、そのために5ビットが必要になり、圧縮データの先頭に配置されます。

出力例

これは、例#4の出力です(で指定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>

쏏𦛏与える<U+C3CF><U+266CF>文字コードとして、私は間違ったことを得ているかもしれません)


2

Python 3、289 + 818 = 1107ポイント

軽くゴルフのみ。

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

合計コードサイズは289バイトで、指定された6135バイトを818個のUnicode文字にエンコードします。合計出力バイト数は3201バイトで、元の入力よりも大幅に少なくなります。

zlibを使用してエンコードし、次にUnicodeエンコードを使用します。サロゲートを回避するために、いくつかの追加のロジックが必要でした(Pythonが実際に嫌っています)。

less(37 Unicode文字)で見られる#4の出力例:

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>

テスト用のドライバープログラム:

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)

出力バイト数:

 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
これが少し不正な圧縮ライブラリを使用しているという事実ではありませんか?
ベータ崩壊14年

@BetaDecay:それは質問でそれを制限しないので、私はそれが公正なゲームであると考えました。
nneonneo 14年

また、解凍プログラムを含める必要があります。
ベータ崩壊14年

@BetaDecay:pパッカー、uアンパッカーです。
nneonneo 14年

1

Python 2-1141ポイント

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)

コードサイズは 281バイトで、6135バイトを860Unicode文字にエンコードします。

使い方:

エンコードするには:

  1. エンコードする文字列を圧縮します。
  2. 圧縮された文字列を256を基数として解釈します。
  3. 数値をバイナリに変換します。
  4. バイナリを19ビットのグループに分割し、1各ビットの先頭にビットを追加してから、Unicode文字に変換します。

デコードは逆です。

pythonの一部のバージョンでは0xFFFF、までのUnicode文字しか処理できないため、このコードではValueError

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.