使用上下文无关文法压缩数据


9

可以使用直线语法压缩某些类型的数据,例如人工文本或源代码。您基本上可以创建一个语法,该语法的语言中只有一个词-未压缩的数据。在此任务中,您必须编写一个实现此数据压缩方法的程序。

输入项

输入的字符串长度不超过65535字节。确保输入匹配正则表达式[!-~]+(即,至少一个可打印的ASCII字符,不包括空格)。

输入示例

abcabcbcbcabcacacabcabab

输出量

输出是形成规则的一组规则,这些规则描述了一个单词(输入)。每个非终结符均用大于9的十进制数表示。起始符号为符号编号十。下面给出了与示例输入相对应的示例输出;其语法在下面进一步描述:

10=11 11 12 12 11 13 13 11 14 14
11=a 12
12=b c
13=a c
14=a b

每个规则的形式<nonterminal>=<symbol> <symbol> ...在右侧带有任意空格分隔的符号数。每个遵循以下限制并精确导出输入字符串的输出均有效。

限制条件

为了阻止人们做奇怪的事情,我们采取了许多限制措施:

  • 每个非终结符必须在规则的右侧至少出现两次。例如,以下输入语法abcabc不合法,因为规则12仅出现一次:

    10=12
    11=a b c
    12=11 11
    
  • 两个相邻符号的序列在所有规则的所有右侧都不能出现多次,除非它们重叠。例如,abcabcbc由于顺序bc出现两次,因此以下输入语法无效:

    10=11 11 b c
    11=a b c
    

    有效的语法为:

    10=11 11 12
    11=a 12
    12=b c
    
  • 对于每个不超过65535字节的有效输入,您的程序必须在不到一分钟的时间内终止。

  • 与往常一样,您不得使用任何语言功能或任何使解决方案变得微不足道或实现很大一部分的库函数。

样品输入

使用以下C程序生成样本输入。

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv) {
  unsigned int i,j = 0,k;

  if (argc != 3
     || 2 != sscanf(argv[1],"%u",&i)
      + sscanf(argv[2],"%u",&k)) {
    fprintf(stderr,"Usage: %s seed length\n",argv[0]);
    return EXIT_FAILURE;
  }

  srand(i);

  while(j < k) {
    i = rand() & 0x7f;
    if (i > 34 && i != 127) j++, putchar(i);
  }

  return EXIT_SUCCESS;
}

上面程序生成的样本输入通常不会产生良好的压缩结果。考虑使用人工文本或源代码作为示例输入。

获奖标准

这是代码高尔夫;源代码最短的程序为准。为了获得额外的荣誉,编写一个从输出中重构输入的程序。


哈哈。对于kolmogorov复杂性问题,我已经在Java中实现了此版本的一些版本(但没有完善)...
Peter Taylor

@PeterTaylor到底是哪个问题?
FUZxxl 2012年

它不一定找到足够短的答案就值得发布(我正在慢慢添加语法生成策略和语法引擎),但是该项目中的核心脚本在codegolf.stackexchange.com/questions/1682上尝试了它们,codegolf .stackexchange.com / questions / 6043codegolf.stackexchange.com/questions/ 4191codegolf.stackexchange.com/questions/ 4356以及其他一些问题的组成部分。
彼得·泰勒

Answers:


3

GolfScript,111点 108的字符

1/{.}{:^1<{^1$/,2>.{;,)^<.0?)!}*}do-1<.,1>{^1$/[10):10]*0+\+}{;^}if(\}while][0]%.,,]zip{))9+`"="+\~" "*+}%n*

使用GolfScript这是一种非常笨拙的方法。第二个版本的性能比第一个版本好得多。它比预期的代码长得多,但是我的实现嵌套了do-loops,这导致了解释器的问题。

例子:

> abcba
10=a b c b a

> abcabcbc
10=11 11 12
11=a 12
12=b c

> abcabcbcbcabcacacabcabab
10=11 12 12 13 14 14 c 11 15
11=15 13
12=c b
13=14 b
14=c a
15=a b

1

已撤消-算法无法处理所有情况。C,422(已固定,可消除输出中的重复字符和掉字符)

最初的实现,将开始打高尔夫。

由于规则不要求它实际压缩这种简单的朴素方法就可以...

可以在10秒内处理65535长度

n,m[99999];
c,r[99999][2];

g,i,s,t;

main(){
    for(;(m[n]=getchar())>32;n++);

    while(!g){ // loop until no further changes
        g=1;
        for(s=0;s<n-1;s++) {
            for(t=s+2;t<n-1;t++)if(m[s]==m[t]&&m[s+1]==m[t+1]){
                // create rule
                r[c][0]=m[s];
                r[c++][1]=m[s+1];
                g=0;
                // substitute
                for(i=t=s;i<n;i++){
                    if(m[i]==r[c-1][0]&&m[i+1]==r[c-1][1]){
                        m[t++]=-c;
                        i++;
                    }else
                        m[t++]=m[i];
                }
                n=t;
            }
        }
    }

    for(s=-1;s<c;s++){
        printf("%d=",s+11);
        for(t=0;t<(s<0?n:2);t++){
            i=(s<0?m:r[s])[t];
            i<0?printf("%d ",10-i):printf("%c ",i);
        }
        printf("\n");
    }

}

样品运行:

echo abcabcbcbcabcacacabcabab | a.out
10=11 12 13 13 12 14 14 12 12 11 
11=a b 
12=c 11 
13=c b 
14=c a


您的代码不符合规范。它产生违反规则的输出,两个字符的序列不能出现两次 ; 考虑输入abcdabcd。同样,您的代码显然从输入流中删除了最后一个字节。查看此处以观察两种效果的示例:ideone.com/3Xvtyv
FUZxxl 2012年

另外,您的样本输出显然是错误的。
FUZxxl 2012年

您是对的-我失败了-下班回来的时候我会看看:P
婴儿兔子

对于我来说,这并不是从输入中删除最后一个字节-而我的示例输出是正确的(对我来说)。让我们玩“发现错误”!
baby-rabbit

您明确发布的示例输出是。规则10的扩展形式以规则14结尾,而规则14依次以“ ca”结尾。最后一个c实际上是结尾之前的5个位置。
FUZxxl 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.