Nén dữ liệu với ngữ pháp miễn phí ngữ cảnh


9

Có thể nén một số loại dữ liệu, chẳng hạn như văn bản của con người hoặc mã nguồn, với các ngữ pháp đường thẳng. Về cơ bản, bạn tạo một ngữ pháp có ngôn ngữ có chính xác một từ - dữ liệu không nén. Trong tác vụ này, bạn phải viết một chương trình thực hiện phương pháp tính toán dữ liệu này.

Đầu vào

Đầu vào là một chuỗi có độ dài không quá 65535 byte. Nó được đảm bảo rằng đầu vào khớp với biểu thức chính quy [!-~]+(tức là ít nhất một ký tự ASCII có thể in được, ngoại trừ khoảng trắng).

Một ví dụ đầu vào là

abcabcbcbcabcacacabcabab

Đầu ra

Đầu ra là một tập hợp các quy tắc tạo thành một ngữ pháp mô tả chính xác một từ (đầu vào). Mỗi nonterminal được ký hiệu bằng một số thập phân lớn hơn 9. Biểu tượng bắt đầu là ký hiệu số mười. Một đầu ra ví dụ tương ứng với đầu vào ví dụ được đưa ra dưới đây; cú pháp của nó được mô tả thêm dưới đây:

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

Mỗi quy tắc có dạng <nonterminal>=<symbol> <symbol> ...với một số ký hiệu được phân tách bằng khoảng trắng tùy ý ở phía bên phải. Mỗi đầu ra tuân theo các hạn chế sau và xuất phát chính xác chuỗi đầu vào là hợp lệ.

Những hạn chế

Để ngăn mọi người làm những việc lạ, một số hạn chế đang diễn ra:

  • Mỗi nonterminal phải xuất hiện ít nhất hai lần ở bên phải của quy tắc. Chẳng hạn, ngữ pháp sau đây cho đầu vào abcabclà bất hợp pháp vì quy tắc 12 chỉ xuất hiện một lần:

    10=12
    11=a b c
    12=11 11
    
  • Không có chuỗi hai biểu tượng liền kề có thể xuất hiện nhiều hơn một lần ở tất cả các phía bên phải của tất cả các quy tắc, ngoại trừ nếu chúng trùng nhau. Chẳng hạn, ngữ pháp sau đây cho đầu vào abcabcbclà bất hợp pháp vì chuỗi bcxuất hiện hai lần:

    10=11 11 b c
    11=a b c
    

    Một ngữ pháp hợp lệ sẽ là:

    10=11 11 12
    11=a 12
    12=b c
    
  • Chương trình của bạn phải chấm dứt sau chưa đầy một phút cho mỗi đầu vào hợp lệ không dài hơn 65535 byte.

  • Như thường lệ, bạn không được sử dụng bất kỳ phương tiện ngôn ngữ nào hoặc bất kỳ chức năng thư viện nào làm cho giải pháp trở nên tầm thường hoặc thực hiện một phần lớn ngôn ngữ đó.

Đầu vào mẫu

Tạo đầu vào mẫu với chương trình C sau.

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

Đầu vào mẫu được tạo bởi chương trình trên thường sẽ không cho kết quả nén tốt. Xem xét sử dụng văn bản của con người hoặc mã nguồn làm đầu vào ví dụ.

Tiêu chí chiến thắng

Đây là mã golf; chương trình có mã nguồn ngắn nhất sẽ thắng. Để có thêm tín dụng, hãy viết chương trình tái tạo đầu vào từ đầu ra.


Ha ha. Tôi đã có một vài phiên bản này được triển khai (nhưng không được đánh gôn) trong Java cho các câu hỏi phức tạp về kolmogorov ...
Peter Taylor

@PeterTaylor Câu hỏi nào chính xác?
FUZxxl

Không nhất thiết phải tìm một câu trả lời đủ ngắn để đáng đăng (Tôi đang thêm các chiến lược tạo ngữ pháp và công cụ ngữ pháp chậm), nhưng kịch bản cốt lõi trong dự án đó đã thử chúng trên codegolf.stackexchange.com/questions/1682 , codegolf .stackexchange.com / question / 6043 , codegolf.stackexchange.com/questions/4191 , codegolf.stackexchange.com/questions/4356 và một vài thành phần của các câu hỏi khác.
Peter Taylor

Câu trả lời:


3

GolfScript, 111 108 ký tự

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

Đây là một cách tiếp cận khá vụng về khi sử dụng GolfScript. Phiên bản thứ hai hoạt động tốt hơn nhiều so với phiên bản ban đầu. Nó dài hơn nhiều so với mã dự định nhưng việc triển khai của tôi có các vòng lặp lồng nhau và điều này gây ra vấn đề với trình thông dịch.

Ví dụ:

> 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

Rút lại - thuật toán không thể xử lý tất cả các trường hợp. C, 422 (đã sửa để loại bỏ các dups trong đầu ra và ký tự bị rớt)

Thực hiện ban đầu, sẽ bắt đầu chơi golf nó.

Vì các quy tắc không yêu cầu nó thực sự nén phương pháp tiếp cận ngây thơ này sẽ làm ...

Có thể xử lý độ dài 65535 trong vòng 10 giây

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");
    }

}

Chạy mẫu:

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


Mã doe của bạn không hoạt động theo đặc điểm kỹ thuật. Nó tạo ra đầu ra vi phạm quy tắc, không có chuỗi hai ký tự có thể xuất hiện hai lần ; xem xét abcdabcd đầu vào. Ngoài ra, mã của bạn rõ ràng sẽ loại bỏ byte cuối cùng khỏi luồng đầu vào. Nhìn vào đây để xem một ví dụ để quan sát cả hai hiệu ứng: ideone.com/3Xvtyv
FUZxxl

Ngoài ra, đầu ra mẫu của bạn rõ ràng là sai.
FUZxxl

Bạn nói đúng - tôi thất bại - Tôi sẽ nhìn vào nó khi tôi nhận được trở lại từ công việc: P
baby-thỏ

Nó không xóa byte cuối cùng khỏi đầu vào đối với tôi - và đầu ra mẫu của tôi là chính xác (đối với tôi) .. Hãy chơi "phát hiện lỗi"!
thỏ con

Đầu ra mẫu bạn đăng chắc chắn là. Hình thức mở rộng của quy tắc 10 kết thúc bằng quy tắc 14 lần lượt kết thúc bằng "ca". C cuối cùng thực sự là 5 vị trí trước khi kết thúc.
FUZxxl
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.