Perl, 438 chars
Lấy cảm hứng từ việc sử dụng nén DEFLATE của Jeff Burdges , mã Ruby đã nén của Venter và sử dụng Lingua :: EN :: Numbers của JB , tôi đã quản lý để nén mục nhập của mình xuống còn 288 ký tự (tốt, byte) bao gồm cả mã giải nén. Vì chương trình chứa một số ký tự không in được, tôi đã cung cấp nó ở định dạng MIME Base64 :
dXNlIENvbXByZXNzOjpabGliO2V2YWwgdW5jb21wcmVzcyAneNolkMFqAkEMhu8+RVgELdaIXmXB
S2/FFyhF4k7cHTqTsclMZd++M3pJvo+QH5JiDJ9exkKrj/PqXOKV1bod77qj9b2UeGBZ7w/bpd9s
3rCDruf3uWtwS3qS/vfROy0xsho+oWbB3d+b19YsJHWGhIHp5eQ8GzqSoWkk/xxHH36a24OkuT38
K21kNm77ND81BceCWtlgoBAq4NWrM7gpyzDhxGKQi+bA6NIfG5K4/mg0d0kgTwwdvi67JHVeKKyX
l3acoxnSDYZJveVIBnGGrIUh1BQYqZacIDKc5Gvpt1vEk3wT3EmzejcyeIGqTApZmRftR7BH3B8W
/5Aze7In
Để giải mã chương trình, bạn có thể sử dụng tập lệnh Perl của trình trợ giúp sau:
use MIME::Base64;
print decode_base64 $_ while <>;
Lưu đầu ra trong một tệp có tên 12days.pl
và chạy nó với perl -M5.01 12days.pl
. Như đã lưu ý, bạn cần cài đặt mô-đun Lingua :: EN :: Numbers để mã hoạt động.
Trong trường hợp bạn đang tự hỏi, phần có thể đọc được của mã chỉ đơn giản là như thế này:
use Compress::Zlib;eval uncompress '...'
trong đó ...
viết tắt của 254 byte mã Perl được nén RFC 1950 . Không nén, mã dài 361 ký tự và trông như thế này:
use Lingua'EN'Numbers"/e/";s==num2en(12-$i++)." "=e,y"." "for@n=qw=drummers.drumming pipers.piping lords.a.leaping ladies.dancing maids.a.milking swans.a.swimming geese.a.laying golden.rings calling.birds french.hens turtle.doves.and=;say"on the ".num2en_ordinal($_)." day of christmas my true love gave to me @n[$i--..@n]a partridge in a pear tree
"for 1..12
Viết mã này là một loại bài tập golf kỳ lạ: hóa ra sự lặp lại tối đa hóa và giảm thiểu số lượng ký tự riêng biệt được sử dụng quan trọng hơn nhiều so với việc giảm thiểu số lượng ký tự thô khi số liệu có liên quan là kích thước sau khi nén .
Để vắt kiệt vài ký tự cuối cùng, tôi đã viết một chương trình đơn giản để thử các biến thể nhỏ của mã này để tìm ra mã nén tốt nhất. Để nén, tôi đã sử dụng tiện ích KZIP của Ken Silverman , thường mang lại khẩu phần nén tốt hơn (với chi phí tốc độ) so với Zlib tiêu chuẩn ngay cả ở cài đặt nén tối đa. Tất nhiên, vì KZIP chỉ tạo tài liệu lưu trữ ZIP, nên sau đó tôi phải trích xuất luồng DEFLATE thô từ kho lưu trữ và bọc nó trong tiêu đề và tổng kiểm tra RFC 1950. Đây là mã tôi đã sử dụng cho điều đó:
use Compress::Zlib;
use 5.010;
@c = qw(e i n s);
@q = qw( " );
@p = qw( = @ ; , );
@n = ('\n',"\n");
$best = 999;
for$A(qw(e n .)){ for$B(@q){ for$C(@q,@p){ for$D(@p){ for$E(@q,@p){ for$F(qw(- _ . N E)){ for$G("-","-"eq$F?():$F){ for$H(@c){ for$I(@c,@p){ for$N(@n){ for$X(11,"\@$I"){ for$Y('$"','" "',$F=~/\w/?$F:()){ for$Z('".num2en_ordinal($_)."'){
$M="Lingua'EN'Numbers";
$code = q!use MB/A/B;sDDnum2en(12-$H++).YDe,yCFC Cfor@I=qwEdrummersFdrumming pipersFpiping lordsGaGleaping ladiesFdancing maidsGaGmilking swansGaGswimming geeseGaGlaying goldenFrings callingFbirds frenchFhens turtleFdovesFandE;say"on the Z day of christmas my true love gave to me @I[$H--..X]a partridge in a pear treeN"for 1..12!.$/;
$code =~ s/[A-Z]/${$&}/g;
open PL, ">12days.pl" and print PL $code and close PL or die $!;
$output = `kzipmix-20091108-linux/kzip -b0 -y 12days.pl.zip 12days.pl`;
($len) = ($output =~ /KSflating\s+(\d\d\d)/) or die $output;
open ZIP, "<12days.pl.zip" and $zip = join("", <ZIP>) and close ZIP or die $!;
($dfl) = ($zip =~ /12days\.pl(.{$len})/s) or die "Z $len: $code";
$dfl = "x\xDA$dfl" . pack N, adler32($code);
$dfl =~ s/\\(?=[\\'])|'/\\$&/g;
next if $best <= length $dfl;
$best = length $dfl;
$bestcode = $code;
warn "$A$B$C$D$E$F$G$H$I $X $Y $best: $bestcode\n";
open PL, ">12days_best.pl" and print PL "use Compress::Zlib;eval uncompress '$dfl'" and close PL or die $!;
}}}}}}
print STDERR "$A$B$C$D$E$F\r";
}}}}}}}
Nếu cái này trông giống như một cái kluge khủng khiếp, thì đó chính là nó.
Đối với lợi ích lịch sử, đây là giải pháp 438-char ban đầu của tôi, tạo ra đầu ra đẹp hơn, bao gồm ngắt dòng và chấm câu:
y/_/ /,s/G/ing/for@l=qw(twelve_drummers_drummG eleven_pipers_pipG ten_lords-a-leapG nine_ladies_dancG eight_maids-a-milkG seven_swans-a-swimmG six_geese-a-layG five_golden_rGs four_callG_birds three_french_hens two_turtle_doves);s/e?t? .*/th/,s/vt/ft/for@n=@l;@n[9..11]=qw(third second first);say map("\u$_,\n","\nOn the $n[11-$_] day of Christmas,\nMy true love gave to me",@l[-$_..-1]),$_?"And a":A," partridge in a pear tree."for 0..11
Điểm nổi bật của phiên bản này là cặp regexps s/e?t? .*/th/,s/vt/ft/
, cấu trúc thứ tự cho 4 đến 12 từ các hồng y ở đầu dòng quà tặng.
Tất nhiên, mã này cũng có thể được nén bằng thủ thuật Zlib được mô tả ở trên, nhưng hóa ra chỉ đơn giản là nén đầu ra hiệu quả hơn, mang lại chương trình 338 byte sau (ở định dạng Base64, một lần nữa):
dXNlIENvbXByZXNzOjpabGliO3NheSB1bmNvbXByZXNzICd42uWTwU7DMAyG730KP8DGOyA0bsCB
vYBp3MYicSo7W9e3xx3ijCIQDHZIUjn683+/k3ZPAjUSDKxWIeACZYC7qGw1o226hwWqHghSORKM
6FMtkGnT3cKEWpXDSMACCBOhQlWim+7jUKO+SGg5dT8XqAetiSD4nrmPBMDPvXywtllF18OgJH2E
SGJfcR+Ky2KL/b0roMeUWEZ4cXb7biQeGol4LZQUSECdyn4A0vjUBvnMXCcYiYy2uE24ONcvgdOR
pBF9lYDNKObwNnPOTnc5kYjH2JZotyogI4c1Ueb06myXH1S48eYeWbyKgclcJr2D/dnwtfXZ7km8
qOeUiXBysP/VEUrt//LurIGJXCdSWxeHu4JW1ZnS0Ph8XOKloIecSe39w/murYdvbRU+Qyc=
Tôi cũng có một kho lưu trữ gzip 312 byte của lời bài hát, được xây dựng từ cùng một luồng DEFLATE. Tôi cho rằng bạn có thể gọi nó là "kịch bản zcat". :)