【问题标题】:Twitter text compression challengeTwitter 文本压缩挑战
【发布时间】:2010-11-04 02:19:50
【问题描述】:

规则

  1. 您的程序必须有两种模式:编码解码
  2. 编码时:

    1. 您的程序必须将一些人类可读的Latin1 文本作为输入,可能是英文。
      • 忽略标点符号也没关系。
      • 您只需要担心实际的英文单词,而不是 L337。
      • 任何重音字母都可以转换为简单的 ASCII。
      • 您可以选择处理数字的方式。
      • 123
        • 一二三
        • 一百二十三
        • 123
        • 1 2 3
      • 一百二十三
        • 一二三
        • 一百二十三
        • 123
        • 1 2 3
    2. 您的程序必须输出一条可以用以下形式表示的消息

      • U+0000U+10FFFF 范围内的 140 个代码点

        排除非字符:

        • U+FFFE
        • U+FFFF
        • U+nFFFE, U+nFFFF 其中n1–@ 987654337@十六进制
        • U+FDD0U+FDEF
        • U+D800U+DFFF(代理代码点)。

    它可以以您选择的任何合理编码输出; GNU iconv 支持的任何编码都将被认为是合理的, 并且您的平台本机编码或语言环境编码可能是一个不错的选择。

  3. 解码时:

    1. 您的程序应将 编码 模式的输出作为输入。
    2. 文本输出应该是输入文本的近似值。
      • 越接近原文越好。
      • 不需要任何标点符号。
    3. 输出文本应该是人类可读的,同样可能是英语。

      • 可以是 L337,也可以是大声笑。
    4. 解码过程可能无法访问编码过程的任何其他输出 上述指定的输出除外; 也就是说,您无法将文本上传到某处并输出URL 用于下载解码过程,或任何类似的傻事。
  4. 为了用户界面的一致性,您的程序必须表现如下:
    1. 您的程序必须是一个脚本,可以设置为在具有适当解释器的平台上执行, 或者可以编译成可执行文件的程序。
    2. 您的程序必须将encodedecode 作为其第一个参数来设置模式。
    3. 您的程序必须至少以下列方式之一接收输入:
      • 从标准输入中获取输入并在标准输出中产生输出。
        • my-program encode <input.txt >output.utf
        • my-program decode <output.utf >output.txt
      • 从第二个参数命名的文件中获取输入,并在第三个参数命名的文件中生成输出。
        • my-program encode input.txt output.utf
        • my-program decode output.utf output.txt
  5. 对于您的解决方案,请发布:
    1. 您的完整代码和/或托管在其他地方的链接 (如果它很长,或者需要编译很多文件,等等)。
    2. 如果不能从代码中立即看出,则说明其工作原理 或者如果代码很长并且人们会对摘要感兴趣。
    3. 示例文本,包含原始文本、压缩后的文本以及解码后的文本。
    4. 如果您正在构建其他人的想法,请注明出处。 尝试对他人的想法进行改进是可以的,但您必须归因于他们。

这些规则是 Twitter image encoding challenge 规则的变体。

【问题讨论】:

  • SMAZ (github.com/antirez/smaz/tree/master) + BASE64 - 我赢了什么?
  • 请将此设为社区 Wiki。你有一些未决的接近投票,大概是因为它不是。
  • 投票重新开放,假设布拉德吉尔伯特将成为这个社区维基
  • 也许应该有一种投票方式将问题变成社区 wiki,就像您可以投票关闭问题一样。
  • 那么,这些是正确的英文句子吗? abbr txt 说话?大声笑?只有英文单词?或者这些是真正的任意 LATIN1 文本字符串?

标签: unicode twitter compression code-golf


【解决方案1】:

不确定我是否有时间/精力来跟进实际代码,但这是我的想法:

  • 任何一定长度的任意 LATIN 1 字符串都可以简单地编码(甚至不压缩),而不会丢失 140 个字符。天真的估计是 280 个字符,尽管由于竞赛规则中的代码点限制,它可能比这短一些。
  • 略长于上述长度的字符串(假设在 280 到 500 个字符之间)很可能会使用标准压缩技术压缩成足够短的字符串以支持上述编码。

再长一点,我们就会开始丢失文本中的信息。因此,执行以下步骤的最小数量,以将字符串减少到可以使用上述方法压缩/编码的长度。此外,不要在 整个 字符串上执行这些替换,如果仅在 子字符串 上执行它们会使其足够短(我可能会向后遍历字符串)。

  1. 将所有大于 127 的 LATIN 1 字符(主要是重音字母和时髦符号)替换为在非重音字母字符中最接近的等效字符,或者可能使用“#”等通用符号替换
  2. 用等效的小写形式替换所有大写字母
  3. 用空格替换所有非字母数字(任何剩余的符号或标点符号)
  4. 用 0 替换所有数字

好的,现在我们已经消除了尽可能多的多余字符。现在我们要做一些更显着的减少:

  1. 将所有双字母(气球)替换为单个字母(巴隆)。看起来很奇怪,但仍然希望读者能够理解。
  2. 将其他常见的字母组合替换为较短的等效字母组合(CK 与 K、WR 与 R 等)

好的,这就是我们可以做到的,让文本可读。除此之外,让我们看看我们是否可以想出一种方法,使文本类似于原始文本,即使它最终不能可识别(再次执行这个从字符串末尾开始一个字符,当它足够短时停止):

  1. 将所有元音 (aeiouy) 替换为 a
  2. 将所有“高”字母 (bdfhklt) 替换为 l
  3. 将所有“短”字母 (cmnrsvwxz) 替换为 n
  4. 将所有“悬挂”字母 (gjpq) 替换为 p

这应该给我们留下一个由 5 个可能值(a、l、n、p 和空格)组成的字符串,这应该允许我们编码相当长的字符串。

除此之外,我们只需要截断即可。

我能想到的唯一其他技术是对常见的单词或字母组进行基于字典的编码。这可能会给我们一些正确句子带来的好处,但可能不会为任意字符串带来好处。

【讨论】:

    【解决方案2】:

    这是我实际英语的变体。

    每个代码点都有大约 1100000 种可能的状态。嗯,空间很大。

    因此,我们提取所有原始文本并从中获取 Wordnet 同义词集。数字被转换成英文名称(“四十二”)。 1,1M 个状态将允许我们保存同义词集 ID(可以在 0 到 82114 之间)、同义词集内的位置(我想大约 10 个变体)和同义词集类型(这是四种之一 - 名词、动词、形容词、副词) .我们甚至可能有足够的空间来存储单词的原始形式(例如动词时态 id)。

    解码器只是将同义词提供给 Wordnet 并检索相应的单词。

    原文:

    A white dwarf is a small star composed mostly of electron-degenerate matter. Because a
    white dwarf's mass is comparable to that of the Sun and its volume is comparable to that 
    of the Earth, it is very dense.
    

    变成:

    A white dwarf be small star composed mostly electron degenerate matter because white
    dwarf mass be comparable sun IT volume be comparable earth IT be very dense
    

    (使用Online Wordnet 测试)。此“代码”应占用 27 个代码点。 当然,所有像“lol”和“L33T”这样的“胡言乱语”都会永远消失。

    【讨论】:

      【解决方案3】:

      PAQ8O10T

      【讨论】:

        【解决方案4】:

        这是一个简单的例子,它接受一个输入文件并删除所有非单词字符。

        #! perl
        use strict;
        use warnings;
        use 5.010;
        
        
        use Getopt::Long;
        use Pod::Usage;
        use autodie;
        
        my %opts = (
          infile  => '-',
          outfile => '-',
        );
        GetOptions (
          'encode|e'    => \$opts{encode},
          'decode|d'    => \$opts{decode},
          'infile|i=s'  => \$opts{infile},
          'outfile|o=s' => \$opts{outfile},
          'help|h'      => \&help,
          'man|m'       => \&man,
        );
        
        unless(
          # exactly one of these should be set
          $opts{encode} xor $opts{decode}
        ){
          help();
        }
        
        
        {
          my $infile;
          if( $opts{infile} ~~ ['-', '&0'] ){
            $infile = *STDIN{IO};
          }else{
            open $infile, '<', $opts{infile};
          }
        
          my $outfile;
          if( $opts{outfile} ~~ ['-', '&1'] ){
            $outfile = *STDOUT{IO};
          }elsif( $opts{outfile} ~~ '&2' ){
            $outfile = *STDERR{IO};
          }else{
            open $outfile, '>', $opts{outfile};
          }
        
          if( $opts{decode} ){
            while( my $line = <$infile> ){
              chomp $line;
        
              say {$outfile} $line;
            }
          }elsif( $opts{encode} ){
            while( my $line = <$infile> ){
              chomp $line;
        
              $line =~ s/[\W_]+/ /g;
        
              say {$outfile} $line;
            }
          }else{
            die 'How did I get here?';
          }
        }
        
        sub help{
          pod2usage();
        }
        sub man{
          pod2usage(1);
        }
        __END__
        
        =head1 NAME
        
        sample.pl - Using GetOpt::Long and Pod::Usage
        
        =head1 SYNOPSIS
        
        sample.pl [options] [file ...]
        
         Options:
           --help     -h      brief help message
           --man      -m      full documentation
           --encode   -e      encode text
           --decode   -d      decode text
           --infile   -i      input  filename
           --outfile  -o      output filename
        
        =head1 OPTIONS
        
        =over 8
        
        =item B<--help>
        
        Print a brief help message and exits.
        
        =item B<--man>
        
        Prints the manual page and exits.
        
        =item B<--encode>
        
        Removes any character other than /\w/.
        
        =item B<--decode>
        
        Just reads from one file, and writes to the other.
        
        =item B<--infile>
        
        Input filename. If this is '-' or '&0', then read from STDIN instead.
        If you use '&0', you must pass it in with quotes.
        
        =item B<--outfile>
        
        Output filename. If this is '-' or '&1', then write to STDOUT instead.
        If this is '&2', then write to STDERR instead.
        If you use '&1' or '&2', you must pass it in with quotes.
        
        =back
        
        =head1 DESCRIPTION
        
        B<This program> will read the given input file(s) and do something
        useful with the contents thereof.
        
        =cut
        
        echo 你好,这是一些文字 | perl 示例.pl -e 你好这是一些文字

        【讨论】:

        • 如何无损反转编码?
        • 这个例子没有无损压缩,我其实是想鼓励一些有损压缩方案的例子。