เล่นกอล์ฟ“ pre-golfed” ของฉัน


12

พื้นหลัง

สำหรับการส่งของฉันใน C ฉันต้องการเครื่องมือประมวลผล เช่นเดียวกับในหลายภาษาอื่น ๆ ช่องว่างส่วนใหญ่ไม่เกี่ยวข้องในซอร์ส C (แต่ไม่เสมอไป!) - ยังทำให้โค้ดสามารถเข้าใจได้ง่ายขึ้นสำหรับมนุษย์ โปรแกรม C ที่เล่นกอล์ฟอย่างเต็มที่ที่ไม่มีช่องว่างซ้ำซ้อนเดียวมักจะอ่านไม่ได้

ดังนั้นฉันชอบที่จะเขียนรหัสของฉันใน C สำหรับการส่งรวมถึงช่องว่างและบางครั้งความคิดเห็นดังนั้นโปรแกรมเก็บโครงสร้างที่เข้าใจได้ในขณะที่เขียน ขั้นตอนสุดท้ายคือการลบความคิดเห็นทั้งหมดและช่องว่างที่ซ้ำซ้อน นี้เป็นงานที่น่าเบื่อและไม่สนใจซึ่งจริงๆควรจะทำโดยนักศึกษาฝึกงานโปรแกรมคอมพิวเตอร์

งาน

เขียนโปรแกรมหรือฟังก์ชั่นที่กำจัดความคิดเห็นและช่องว่างที่ซ้ำซ้อนจากบางแหล่ง "pre-golfed" C ตามกฎต่อไปนี้:

  • \(ทับขวา) เป็นตัวสุดท้ายในสายเป็นความต่อเนื่องบรรทัด หากคุณพบสิ่งนี้คุณต้องถือว่าบรรทัดต่อไปนี้เป็นส่วนหนึ่งของสายตรรกะเดียวกัน(ตัวอย่างเช่นคุณสามารถลบ\และต่อไปนี้\n(ขึ้นบรรทัดใหม่) อย่างสมบูรณ์ก่อนที่จะทำสิ่งอื่นใด)
  • //ความคิดเห็นที่จะใช้รูปแบบหนึ่งบรรทัดที่เริ่มต้นด้วย ดังนั้นเมื่อต้องการลบออกคุณจะไม่สนใจส่วนที่เหลือของบรรทัดโลจิคัลที่ใดก็ตามที่คุณพบ//นอกสตริงตัวอักษร (ดูด้านล่าง)
  • อักขระช่องว่างคือ(ช่องว่าง), \t(แท็บ) และ\n(ขึ้นบรรทัดใหม่ดังนั้นนี่คือจุดสิ้นสุดของบรรทัดตรรกะ)
  • เมื่อคุณค้นหาลำดับของช่องว่างให้ตรวจสอบอักขระที่ไม่ใช่ช่องว่างที่ล้อมรอบ ถ้า

    • ทั้งคู่เป็นตัวอักษรและตัวเลขหรือขีดล่าง (ช่วง[a-zA-Z0-9_]) หรือ
    • ทั้งสอง+หรือ
    • ทั้งสอง-หรือ
    • สิ่งที่มาก่อนคือ/และสิ่งที่ตามมาคือ*

    จากนั้นแทนที่ลำดับด้วยอักขระช่องว่าง ( )

    มิฉะนั้นให้กำจัดลำดับทั้งหมด

    กฎนี้มีข้อยกเว้นบางประการ :

    • คำสั่งของโปรเซสเซอร์ล่วงหน้าจะต้องปรากฏในบรรทัดของตัวเองในผลลัพธ์ของคุณ สั่ง preprocessor #เป็นสายที่เริ่มต้นด้วย
    • ภายในตัวอักษรสตริงหรือตัวอักษรคุณไม่ควรลบช่องว่างใด ๆ ใด ๆ"(อ้างดับเบิล) / '(อ้างเดียว) ที่ไม่ได้นำหน้าได้โดยตรงโดยเป็นเลขคี่ backslashes ( \) เริ่มต้นหรือปลายสตริงตัวอักษร / ตัวอักษรตัวอักษร คุณรับประกันได้ว่าสตริงและตัวอักษรจะลงท้ายด้วยบรรทัดเดียวกันกับที่เริ่มต้น สายอักขระตัวอักษรและตัวอักษรของตัวละครไม่สามารถซ้อนกันดังนั้น'ภายในตัวอักษรสตริง , เช่นเดียวกับ"ภายในของตัวละครตัวอักษรไม่ได้มีความหมายพิเศษใด ๆ

ข้อกำหนด I / O

อินพุตและเอาต์พุตต้องเป็นลำดับอักขระ (สตริง) รวมถึงอักขระขึ้นบรรทัดใหม่หรืออาร์เรย์ / รายการสตริงที่ไม่มีอักขระขึ้นบรรทัดใหม่ หากคุณเลือกที่จะใช้อาร์เรย์ / รายการแต่ละองค์ประกอบแสดงถึงบรรทัดดังนั้นการขึ้นบรรทัดใหม่ที่มีนัยหลังจากที่แต่ละองค์ประกอบ

คุณอาจสันนิษฐานว่าอินพุตเป็นซอร์สโค้ดโปรแกรม C ที่ถูกต้อง นอกจากนี้ยังหมายความว่ามีเพียงอักขระ ASCII ที่พิมพ์ได้แท็บและการขึ้นบรรทัดใหม่ พฤติกรรมที่ไม่ได้กำหนดบนอินพุตที่มีรูปแบบไม่ได้รับอนุญาต

ชั้นนำและต่อท้ายช่องว่าง / บรรทัดว่างจะไม่ได้รับอนุญาต

กรณีทดสอบ

  1. อินพุต

    main() {
        printf("Hello, World!"); // hi
    }
    

    เอาท์พุต

    main(){printf("Hello, World!");}
    
  2. อินพุต

    #define max(x, y) \
        x > y ? x : y
    #define I(x) scanf("%d", &x)
    a;
    b; // just a needless comment, \
            because we can!
    main()
    {
        I(a);
        I(b);
        printf("\" max \": %d\n", max(a, b));
    }
    

    เอาท์พุต

    #define max(x,y)x>y?x:y
    #define I(x)scanf("%d",&x)
    a;b;main(){I(a);I(b);printf("\" max \": %d\n",max(a,b));}
    
  3. อินพุต

    x[10];*c;i;
    main()
    {
        int _e;
        for(; scanf("%d", &x) > 0 && ++_e;);
        for(c = x + _e; c --> x; i = 100 / *x, printf("%d ", i - --_e));
    }
    

    เอาท์พุต

    x[10];*c;i;main(){int _e;for(;scanf("%d",&x)>0&&++_e;);for(c=x+_e;c-->x;i=100/ *x,printf("%d ",i- --_e));}
    
  4. อินพุต

    x;
    #include <stdio.h>
    int main()
    {
        puts("hello // there");
    }
    

    เอาท์พุต

    x;
    #include<stdio.h>
    int main(){puts("hello // there");}
    
  5. อินพุต (ตัวอย่างจริง)

    // often used functions/keywords:
    #define P printf(
    #define A case
    #define B break
    
    // loops for copying rows upwards/downwards are similar -> macro
    #define L(i, e, t, f, s) \
            for (o=i; o e;){ strcpy(l[o t], l[o f]); c[o t]=c[s o]; }
    
    // range check for rows/columns is similar -> macro
    #define R(m,o) { return b<1|b>m ? m o : b; }
    
    // checking for numerical input is needed twice (move and print command):
    #define N(f) sscanf(f, "%d,%d", &i, &j) || sscanf(f, ",%d", &j)
    
    // room for 999 rows with each 999 cols (not specified, should be enough)
    // also declare "current line pointers" (*L for data, *C for line length),
    // an input buffer (a) and scratch variables
    r, i, j, o, z, c[999], *C, x=1, y=1;
    char a[999], l[999][999], (*L)[999];
    
    // move rows down from current cursor position
    D()
    {
        L(r, >y, , -1, --)
        r++ ? strcpy(l[o], l[o-1]+--x), c[o-1]=x, l[o-1][x]=0 : 0;
        c[y++] = strlen(l[o]);
        x=1;
    }
    
    // move rows up, appending uppermost to current line
    U()
    {
        strcat(*L, l[y]);
        *C = strlen(*L);
        L(y+1, <r, -1, , ++)
        --r;
        *l[r] = c[r] = 0;
    }
    
    // normalize positions, treat 0 as max
    X(b) R(c[y-1], +1)
    Y(b) R(r, )
    
    main()
    {
        for(;;) // forever
        {
            // initialize z as current line index, the current line pointers,
            // i and j for default values of positioning
            z = i = y;
            L = l + --z;
            C = c + z;
            j = x;
    
            // prompt:
            !r || y/r && x > *C
                ? P "end> ")
                : P "%d,%d> ", y, x);
    
            // read a line of input (using scanf so we don't need an include)
            scanf("%[^\n]%*c", a)
    
                // no command arguments -> make check easier:
                ? a[2] *= !!a[1],
    
                // numerical input -> have move command:
                // calculate new coordinates, checking for "relative"
                N(a)
                    ? y = Y(i + (i<0 | *a=='+') * y)
                        , x = X(j + (j<0 || strchr(a+1, '+')) * x)
                    :0
    
                // check for empty input, read single newline
                // and perform <return> command:
                : ( *a = D(), scanf("%*c") );
    
            switch(*a)
            {
                A 'e':
                    y = r;
                    x = c[r-1] + 1;
                    B;
    
                A 'b':
                    y = 1;
                    x = 1;
                    B;
    
                A 'L':
                    for(o = y-4; ++o < y+2;)
                        o<0 ^ o<r && P "%c%s\n", o^z ? ' ' : '>', l[o]);
                    for(o = x+1; --o;)
                        P " ");
                    P "^\n");
                    B;
    
                A 'l':
                    puts(*L);
                    B;
    
                A 'p':
                    i = 1;
                    j = 0;
                    N(a+2);
                    for(o = Y(i)-1; o<Y(j); ++o)
                        puts(l[o]);
                    B;
    
                A 'A':
                    y = r++;
                    strcpy(l[y], a+2);
                    x = c[y] = strlen(a+2);
                    ++x;
                    ++y;
                    B;
    
                A 'i':
                    D();
                    --y;
                    x=X(0);
                    // Commands i and r are very similar -> fall through
                    // from i to r after moving rows down and setting
                    // position at end of line:
    
                A 'r':
                    strcpy(*L+x-1, a+2);
                    *C = strlen(*L);
                    x = 1;
                    ++y > r && ++r;
                    B;
    
                A 'I':
                    o = strlen(a+2);
                    memmove(*L+x+o-1, *L+x-1, *C-x+1);
                    *C += o;
                    memcpy(*L+x-1, a+2, o);
                    x += o;
                    B;
    
                A 'd':
                    **L ? **L = *C = 0, x = 1 : U();
                    y = y>r ? r : y;
                    B;
    
                A 'j':
                    y<r && U();
            }
        }
    }
    

    เอาท์พุต

    #define P printf(
    #define A case
    #define B break
    #define L(i,e,t,f,s)for(o=i;o e;){strcpy(l[o t],l[o f]);c[o t]=c[s o];}
    #define R(m,o){return b<1|b>m?m o:b;}
    #define N(f)sscanf(f,"%d,%d",&i,&j)||sscanf(f,",%d",&j)
    r,i,j,o,z,c[999],*C,x=1,y=1;char a[999],l[999][999],(*L)[999];D(){L(r,>y,,-1,--)r++?strcpy(l[o],l[o-1]+--x),c[o-1]=x,l[o-1][x]=0:0;c[y++]=strlen(l[o]);x=1;}U(){strcat(*L,l[y]);*C=strlen(*L);L(y+1,<r,-1,,++)--r;*l[r]=c[r]=0;}X(b)R(c[y-1],+1)Y(b)R(r,)main(){for(;;){z=i=y;L=l+--z;C=c+z;j=x;!r||y/r&&x>*C?P"end> "):P"%d,%d> ",y,x);scanf("%[^\n]%*c",a)?a[2]*=!!a[1],N(a)?y=Y(i+(i<0|*a=='+')*y),x=X(j+(j<0||strchr(a+1,'+'))*x):0:(*a=D(),scanf("%*c"));switch(*a){A'e':y=r;x=c[r-1]+1;B;A'b':y=1;x=1;B;A'L':for(o=y-4;++o<y+2;)o<0^o<r&&P"%c%s\n",o^z?' ':'>',l[o]);for(o=x+1;--o;)P" ");P"^\n");B;A'l':puts(*L);B;A'p':i=1;j=0;N(a+2);for(o=Y(i)-1;o<Y(j);++o)puts(l[o]);B;A'A':y=r++;strcpy(l[y],a+2);x=c[y]=strlen(a+2);++x;++y;B;A'i':D();--y;x=X(0);A'r':strcpy(*L+x-1,a+2);*C=strlen(*L);x=1;++y>r&&++r;B;A'I':o=strlen(a+2);memmove(*L+x+o-1,*L+x-1,*C-x+1);*C+=o;memcpy(*L+x-1,a+2,o);x+=o;B;A'd':**L?**L=*C=0,x=1:U();y=y>r?r:y;B;A'j':y<r&&U();}}}
    

นี่คือดังนั้นคำตอบที่ถูกต้องสั้นที่สุด (เป็นไบต์) จึงจะชนะ



ขอให้เรายังคงอภิปรายนี้ในการแชท
DLosc

คำตอบ:


4

Pip , 148 135 133 138 ไบต์

aRM"\
"R`("|').*?(?<!\\)(\\\\)*\1`{lPBaC:++i+191}R[`//.*``#.*`{X*aJw.`(?=`}.')M[A`\w`RL2"++""--""/*"]w`¶+`'·C(192+,#l)][x_WR'¶{aRw'·}xnsl]

ไบต์จะถูกนับในCP-1252ดังนั้นและ·เป็นหนึ่งไบต์ในแต่ละ โปรดทราบว่าสิ่งนี้คาดว่ารหัส C เป็นอาร์กิวเมนต์บรรทัดคำสั่งเดียวซึ่ง (ในบรรทัดคำสั่งจริง) จะต้องใช้ลำดับการหลบหนีมากมาย ลองใช้งานออนไลน์ง่ายกว่านี้มาก!

คำอธิบายของเวอร์ชันที่ไม่อัปโหลดเล็กน้อย

รหัสนี้เป็นพวงของการแทนที่ด้วยเทคนิคสองสามอย่าง

แบ็กสแลชต่อเนื่อง

เราRMทุกคนเกิดขึ้นของสตริงตัวอักษร

"\
"

นั่นคือแบ็กสแลชตามด้วยบรรทัดใหม่

สตริงและตัวอักษรตัวอักษร

เราใช้การแทนที่ regex ด้วยฟังก์ชันการเรียกกลับ:

`("|').*?(?<!\\)(\\\\)*\1`

{
 lPBa
 C(++i + 191)
}

regex ตรงกับเครื่องหมายคำพูดเดี่ยวหรือคู่แล้วตามด้วยคำว่าไม่ใช่โลภ.*?ที่ตรงกับ 0 หรือมากกว่าตัวอักษรน้อยที่สุด เรามีมุมมองเชิงลบเพื่อให้แน่ใจว่าอักขระก่อนหน้าไม่ใช่แบ็กสแลช จากนั้นเราจับคู่แบ็กสแลชจำนวนคู่ตามด้วยตัวคั่นเปิดอีกครั้ง

ฟังก์ชั่นการโทรกลับใช้เวลาสตริง / lตัวอักษรตัวอักษรและผลักดันให้มันไปทางด้านหลังของรายการ จากนั้นจะส่งคืนอักขระที่ขึ้นต้นด้วยรหัสอักขระ 192 ( À) และเพิ่มขึ้นด้วยการแทนที่ตัวอักษรแต่ละตัว ดังนั้นรหัสจะถูกแปลงเช่น:

printf("%c", '\'');

printf(À, Á);

อักขระการแทนที่เหล่านี้รับประกันว่าจะไม่เกิดขึ้นในซอร์สโค้ดซึ่งหมายความว่าเราสามารถสำรองอักขระสำรองในภายหลังได้อย่างไม่น่าสงสัย

ความคิดเห็น

`//.*`

x

การจับคู่ regex //รวมทุกอย่างจนถึงบรรทัดใหม่และแทนที่ด้วยx(ตั้งค่าล่วงหน้าเป็นสตริงว่าง)

คำสั่งของโปรเซสเซอร์ล่วงหน้า

`#.*`

_WR'¶

ห่อวิ่งของตัวละครที่ไม่ใช่การขึ้นบรรทัดใหม่ที่เริ่มต้นด้วยเครื่องหมายปอนด์ใน

ช่องว่างที่ไม่ควรถูกกำจัด

{
 (
  X*a J w.`(?=`
 ) . ')
}
M
[
 A`\w` RL 2
 "++"
 "--"
 "/*"
]

{
 a R w '·
}

มีหลายอย่างเกิดขึ้นที่นี่ ส่วนแรกสร้างรายการของ regexes นี้เพื่อแทนที่:

[
 `(?a)\w\s+(?=(?a)\w)`  Whitespace surrounded by [a-zA-Z_]
 `\+\s+(?=\+)`          Whitespace surrounded by +
 `\-\s+(?=\-)`          Whitespace surrounded by -
 `\/\s+(?=\*)`          Whitespace surrounded by / *
]

หมายเหตุการใช้ lookaheads เพื่อให้ตรงกับตัวอย่างเช่นเพียงในe define P printfด้วยวิธีนี้การแข่งขันนี้ไม่ได้ใช้งานPซึ่งหมายความว่าการแข่งขันครั้งต่อไปสามารถใช้งานได้

เราสร้างรายการของ regexes นี้โดยการทำแผนที่ฟังก์ชั่นไปยังรายการที่มีรายการ

[
 [`(?a)\w` `(?a)\w`]
 "++"
 "--"
 "/*"
]

และฟังก์ชั่นทำสิ่งนี้กับแต่ละองค์ประกอบ:

(X*aJw.`(?=`).')
 X*a              Map unary X to elements/chars a: converts to regex, escaping as needed
                  Regexes like `\w` stay unchanged; strings like "+" become `\+`
    J             Join the resulting list on:
     w             Preset variable for `\s+`
      .`(?=`       plus the beginning of the lookahead syntax
(           ).')  Concatenate the closing paren of the lookahead

เมื่อเรามี regexes ของเราเราจะแทนที่สิ่งที่เกิดขึ้นด้วยฟังก์ชัน callback นี้:

{aRw'·}

·ซึ่งแทนที่การทำงานของช่องว่างในการแข่งขันแต่ละครั้งด้วย

การกำจัดและกำจัดช่องว่าง

[w `¶+` '·]

[x n s]

การทดแทนที่ต่อเนื่องกันสามครั้งจะแทนที่การเรียกใช้ whitespace ( w) ที่ว่างสำหรับสตริงที่ว่าง ( x), การเรียกใช้สำหรับการขึ้นบรรทัดใหม่และ·สำหรับการเว้นวรรค

การทดแทนกลับของสตริงและตัวอักษรตัวอักษร

C(192+,#l)

l

เราสร้างรายการของตัวละครทั้งหมดที่เราใช้แทนตัวอักษรโดยการใช้192 + range(len(l))และแปลงเป็นตัวอักษร lจากนั้นเราจะสามารถแทนที่แต่ละเหล่านี้มีอยู่ในตัวอักษรที่เกี่ยวข้อง

และนั่นมัน! สตริงผลลัพธ์ถูกพิมพ์อัตโนมัติ


เยี่ยมมากฉันประทับใจ (+1)! การรวม//ตัวอักษรภายในสตริงเป็นความคิดที่ดีสำหรับกรณีทดสอบฉันจะเพิ่มอีกหนึ่งอย่างในวันพรุ่งนี้
เฟลิกซ์ Palmen

อืม ... ตอนนี้ฉันพบข้อผิดพลาดเล็กน้อยที่นี่เช่นกัน ...
เฟลิกซ์ Palmen

ฉันจะเลือกผู้ชนะหลังจาก 14 วัน (สิ้นสัปดาห์หน้า) และโซลูชันของคุณจะเป็นผู้สมัครคนแรกถ้าคุณหาเวลาแก้ไขข้อผิดพลาดนี้ ตอนนี้คุณมีคะแนนต่ำสุด :)
เฟลิกซ์ Palmen

1
แก้ไข @ FelixPalmen แล้ว!
DLosc

7

Haskell , 327 360 418 394 ไบต์

g.(m.w.r.r=<<).lines.f
n:c:z="\n#_0123456789"++['A'..'Z']++['a'..'z']
(!)x=elem x
f('\\':'\n':a)=f a
f(a:b)=a:f b
f a=a
m('#':a)=c:a++[n]
m a=a
g(a:'#':b)=a:[n|a/=n]++c:g b
g(a:b)=a:g b
g a=a
s=span(!" \t")
r=reverse.snd.s
l n(a:b)d|a==d,n=a:w(snd$s b)|1>0=a:l(not$n&&a=='\\')b d
w('/':'/':_)=[]
w(a:b)|a!"\"'"=a:l(1>0)b a|(p,q:u)<-s b=a:[' '|p>"",a!z&&q!z||[a,q]!words"++ -- /*"]++w(q:u)
w a=a

ลองออนไลน์!

มันสนุกมากที่จะเขียน! ก่อนอื่นfฟังก์ชันจะผ่านและลบแบ็กสแลชทั้งหมดที่ท้ายบรรทัดแล้วlinesแบ่งออกเป็นรายการสตริงที่บรรทัดใหม่ จากนั้นเราแมปกลุ่มฟังก์ชั่นลงบนเส้นและเชื่อมต่อมันเข้าด้วยกัน ฟังก์ชั่นเหล่านั้นแถบช่องว่างด้านซ้าย ( t) และจากขวา ( r.t.rที่rเป็นreverse); ลบช่องว่างออกจากตรงกลางโดยไม่สนใจสตริงและตัวอักษรตัวอักษรรวมถึงการลบความคิดเห็น ( w); และในที่สุดก็เพิ่มอักขระขึ้นบรรทัดใหม่ต่อท้ายหากบรรทัดขึ้นต้นด้วย # หลังจากที่ทุกบรรทัดถูกต่อกันกลับเข้าหากันแล้วgจะมองหาอักขระ # ตัวและทำให้แน่ใจว่าพวกเขาจะขึ้นบรรทัดใหม่

wซับซ้อนเล็กน้อยดังนั้นฉันจะอธิบายเพิ่มเติม ครั้งแรกที่ฉันตรวจสอบ "//" เนื่องจากwฉันรู้ว่าฉันไม่ได้อยู่ในสตริงตามตัวอักษรฉันรู้ว่านี่เป็นความคิดเห็นดังนั้นฉันจึงวางส่วนที่เหลือของบรรทัด ต่อไปฉันจะตรวจสอบว่าหัวเป็นตัวคั่นสำหรับสตริงหรือตัวอักษร ถ้าเป็นฉันจะเติมมันและส่งผ่านกระบองlที่วิ่งผ่านตัวละครติดตามสถานะ "หลบหนี" nซึ่งจะเป็นจริงถ้ามีสแลชติดต่อกันเป็นจำนวนมาก เมื่อlตรวจพบตัวคั่นและไม่ได้อยู่ในสถานะหลบหนีมันจะส่งผ่านกระบองกลับไปที่wตัดเพื่อกำจัดช่องว่างหลังจากตัวอักษรเพราะwคาดว่าอักขระตัวแรกจะไม่เป็นช่องว่าง เมื่อไหร่wไม่พบตัวคั่นที่ใช้ span เพื่อค้นหาช่องว่างในส่วนท้าย หากมีสิ่งใดที่มันจะตรวจสอบว่าตัวละครที่อยู่รอบตัวมันไม่สามารถนำมาติดต่อและแทรกช่องว่างถ้าเป็นเช่นนั้น จากนั้นจะเกิดขึ้นอีกครั้งหลังจากที่ช่องว่างสิ้นสุดลง หากไม่มีช่องว่างไม่มีการแทรกช่องว่างและมันยังคงดำเนินต่อไป

แก้ไข: ขอบคุณมากที่ @DLosc ชี้ให้เห็นข้อผิดพลาดในโปรแกรมของฉันที่จริง ๆ แล้วก็นำไปสู่วิธีที่ฉันจะย่อให้สั้นลงเช่นกัน! ไชโยสำหรับการจับคู่รูปแบบ!

EDIT2: ฉันเป็นคนงี่เง่าที่อ่านสเป็คไม่จบ! ขอบคุณอีกครั้งที่ DLosc ชี้ให้เห็น!

edit3: เพียงแค่สังเกตเห็นบางสิ่งที่น่ารำคาญลดประเภทที่เปิดe=elemเข้ามาด้วยเหตุผลบางอย่างจึงทำลายบนChar->[Char]->Bool e[a,q]ฉันต้องเพิ่มลายเซ็นประเภทเพื่อบังคับให้ถูกต้อง ไม่มีใครรู้ว่าฉันจะแก้ไขได้อย่างไร ฉันไม่เคยมีปัญหานี้ใน Haskell มาก่อน TIO

EDIT4: แก้ไขด่วนสำหรับข้อผิดพลาด @ FelixPalmen พบฉัน ฉันอาจลองเล่นกอล์ฟในภายหลังเมื่อฉันมีเวลา

EDIT5: -24 ไบต์ขอบคุณ @Lynn! ขอบคุณ! ฉันไม่ทราบว่าคุณสามารถมอบหมายสิ่งต่าง ๆ ในขอบเขตทั่วโลกโดยใช้การจับคู่รูปแบบเหมือนn:c:z=...ที่เจ๋งจริงๆ! นอกจากนี้ยังมีความคิดที่ดีในการสร้างโอเปอเรเตอร์เพื่อelemหวังว่าฉันจะคิดอย่างนั้น


1
ผมบีบออก 24 ไบต์
Lynn

2
คุณกำลังวิ่งเข้าไปในข้อ จำกัด monomorphism หวั่น ; การกำหนดe x y=elem x y(หรือแม้กระทั่งe x=elem x) แก้ปัญหาของคุณ (ฉันเปลี่ยนชื่อeเป็นโอเปอเรเตอร์, (!).)
ลินน์

3

C, 497 494 490 489 ไบต์

เนื่องจากเรากำลังประมวลผล C ลองทำโดยใช้ C! ฟังก์ชั่นf()รับอินพุตจากตัวชี้ถ่านpและเอาต์พุตไปยังตัวชี้qและถือว่าอินพุตอยู่ใน ASCII:

#define O*q++
#define R (r=*p++)
#define V(c)(isalnum(c)||c==95)
char*p,*q,r,s,t;d(){isspace(r)?g():r==47&&*p==r?c(),g():r==92?e():(O=s=r)==34?b():r==39?O=R,a():r?a():(O=r);}a(){R;d();}b(){((O=R)==34?a:r==92?O=R,b:b)();}c(){while(R-10)p+=r==92;}e(){R-10?s=O=92,O=r,a():h();}j(){(!isspace(R)?r==47&&*p==r?c(),j:(t=r==35,d):j)();}f(){t=*p==35;j();}i(){V(s)&&V(r)||s==47&&r==42||(s==43||s==45)&&r==s&&*p==s?O=32:0;d();}h(){isspace(R)?g():i();}g(){(r==10?t?O=r,j:*p==35?s-10?s=O=r,j:0:h:h)();}

เราคิดว่าไฟล์นั้นมีรูปแบบที่ถูกต้อง - สตริงและตัวอักษรถูกปิดและหากมีความคิดเห็นในบรรทัดสุดท้ายจะต้องมีการขึ้นบรรทัดใหม่เพื่อปิดมัน

คำอธิบาย

รุ่นก่อนตีกอล์ฟมีความชัดเจนมากกว่าเดิมเล็กน้อยฉันกลัว:

#define O *q++=
#define R (r=*p++)
#define V(c)(isalnum(c)||c=='_')
char*p,*q,r,s,t;
d(){isspace(r)?g():r=='/'&&*p==r?c(),g():r=='\\'?e():(O s=r)=='"'?b():r=='\''?O R,a():r?a():(O r);}
a(){R;d();}
b(){((O R)=='"'?a:r=='\\'?O R,b:b)();}
c(){while(R!='\n')p+=r=='\\';}
e(){R!='\n'?s=O'\\',O r,a():h();}
j(){(!isspace(R)?r=='/'&&*p==r?c(),j:(t=r=='#',d):j)();}
f(){t=*p=='#';j();}
i(){V(s)&&V(r)||s=='/'&&r=='*'||(s=='+'||s=='-')&&r==s&&*p==s?O' ':0;d();}
h(){isspace(R)?g():i();}
g(){(r=='\n'?t?O r,j:*p=='#'?s!='\n'?s=O r,j:0:h:h)();}

ใช้เครื่องมือสถานะโดยเรียกซ้ำหาง แมโครและตัวแปรตัวช่วยคือ

  • Oสำหรับo utput
  • Rเพื่อRป้อนข้อมูลลงในอี๊ดr
  • Vเพื่อกำหนดอักขระตัวระบุv alid (ตั้งแต่!isalnum('_'))
  • pและq- พอยน์เตอร์ I / O ตามที่อธิบายไว้
  • r- ตัวอักษรตัวสุดท้ายจะเป็นอาอี๊ด
  • s- s aved ตัวละครที่ไม่ใช่ช่องว่างที่ผ่านมา
  • t- t ag เมื่อทำงานกับคำสั่ง preprocessor

รัฐของเราคือ

  • a() - รหัส C ปกติ
  • b() - ตัวอักษรสตริง
  • c() - แสดงความคิดเห็น
  • d() - รหัส C ปกติหลังจากอ่าน r
  • e() - ลำดับหลบหนี
  • f() - สถานะเริ่มต้น (ฟังก์ชั่นหลัก)
  • g() - ในช่องว่าง
  • h()- ในช่องว่าง - ส่งไปที่g()หรือi()
  • i() - ทันทีหลังช่องว่าง - เราต้องใส่อักขระเว้นวรรคหรือไม่
  • j() - ช่องว่างเริ่มต้น - ห้ามแทรกอักขระเว้นวรรค

โปรแกรมทดสอบ

#define DEMO(code)                              \
    do {                                        \
        char in[] = code;                       \
        char out[sizeof in];                    \
        p=in;q=out;f();                         \
        puts("vvvvvvvvvv");                     \
        puts(out);                              \
        puts("^^^^^^^^^^");                     \
    } while (0)

#include<stdio.h>
#include<stdlib.h>
int main()
{
    DEMO(
         "main() {\n"
         "    printf(\"Hello, World!\"); // hi\n"
         "}\n"
         );
    DEMO(
         "#define max(x, y)                               \\\n"
         "    x > y ? x : y\n"
         "#define I(x) scanf(\"%d\", &x)\n"
         "a;\n"
         "b; // just a needless comment, \\\n"
         "        because we can!\n"
         "main()\n"
         "{\n"
         "    I(a);\n"
         "    I(b);\n"
         "    printf(\"\\\" max \\\": %d\\n\", max(a, b));\n"
         "}\n"
         );
    DEMO(
         "x[10];*c;i;\n"
         "main()\n"
         "{\n"
         "    int _e;\n"
         "    for(; scanf(\"%d\", &x) > 0 && ++_e;);\n"
         "    for(c = x + _e; c --> x; i = 100 / *x, printf(\"%d \", i - --_e));\n"
         "}\n"
         );
    DEMO(
         "// often used functions/keywords:\n"
         "#define P printf(\n"
         "#define A case\n"
         "#define B break\n"
         "\n"
         "// loops for copying rows upwards/downwards are similar -> macro\n"
         "#define L(i, e, t, f, s) \\\n"
         "        for (o=i; o e;){ strcpy(l[o t], l[o f]); c[o t]=c[s o]; }\n"
         "\n"
         "// range check for rows/columns is similar -> macro\n"
         "#define R(m,o) { return b<1|b>m ? m o : b; }\n"
         "\n"
         "// checking for numerical input is needed twice (move and print command):\n"
         "#define N(f) sscanf(f, \"%d,%d\", &i, &j) || sscanf(f, \",%d\", &j)\n"
         "\n"
         "// room for 999 rows with each 999 cols (not specified, should be enough)\n"
         "// also declare \"current line pointers\" (*L for data, *C for line length),\n"
         "// an input buffer (a) and scratch variables\n"
         "r, i, j, o, z, c[999], *C, x=1, y=1;\n"
         "char a[999], l[999][999], (*L)[999];\n"
         "\n"
         "// move rows down from current cursor position\n"
         "D()\n"
         "{\n"
         "    L(r, >y, , -1, --)\n"
         "    r++ ? strcpy(l[o], l[o-1]+--x), c[o-1]=x, l[o-1][x]=0 : 0;\n"
         "    c[y++] = strlen(l[o]);\n"
         "    x=1;\n"
         "}\n"
         "\n"
         "// move rows up, appending uppermost to current line\n"
         "U()\n"
         "{\n"
         "    strcat(*L, l[y]);\n"
         "    *C = strlen(*L);\n"
         "    L(y+1, <r, -1, , ++)\n"
         "    --r;\n"
         "    *l[r] = c[r] = 0;\n"
         "}\n"
         "\n"
         "// normalize positions, treat 0 as max\n"
         "X(b) R(c[y-1], +1)\n"
         "Y(b) R(r, )\n"
         "\n"
         "main()\n"
         "{\n"
         "    for(;;) // forever\n"
         "    {\n"
         "        // initialize z as current line index, the current line pointers,\n"
         "        // i and j for default values of positioning\n"
         "        z = i = y;\n"
         "        L = l + --z;\n"
         "        C = c + z;\n"
         "        j = x;\n"
         "\n"
         "        // prompt:\n"
         "        !r || y/r && x > *C\n"
         "            ? P \"end> \")\n"
         "            : P \"%d,%d> \", y, x);\n"
         "\n"
         "        // read a line of input (using scanf so we don't need an include)\n"
         "        scanf(\"%[^\\n]%*c\", a)\n"
         "\n"
         "            // no command arguments -> make check easier:\n"
         "            ? a[2] *= !!a[1],\n"
         "\n"
         "            // numerical input -> have move command:\n"
         "            // calculate new coordinates, checking for \"relative\"\n"
         "            N(a)\n"
         "                ? y = Y(i + (i<0 | *a=='+') * y)\n"
         "                    , x = X(j + (j<0 || strchr(a+1, '+')) * x)\n"
         "                :0\n"
         "\n"
         "            // check for empty input, read single newline\n"
         "            // and perform <return> command:\n"
         "            : ( *a = D(), scanf(\"%*c\") );\n"
         "\n"
         "        switch(*a)\n"
         "        {\n"
         "            A 'e':\n"
         "                y = r;\n"
         "                x = c[r-1] + 1;\n"
         "                B;\n"
         "\n"
         "            A 'b':\n"
         "                y = 1;\n"
         "                x = 1;\n"
         "                B;\n"
         "\n"
         "            A 'L':\n"
         "                for(o = y-4; ++o < y+2;)\n"
         "                    o<0 ^ o<r && P \"%c%s\\n\", o^z ? ' ' : '>', l[o]);\n"
         "                for(o = x+1; --o;)\n"
         "                    P \" \");\n"
         "                P \"^\\n\");\n"
         "                B;\n"
         "\n"
         "            A 'l':\n"
         "                puts(*L);\n"
         "                B;\n"
         "\n"
         "            A 'p':\n"
         "                i = 1;\n"
         "                j = 0;\n"
         "                N(a+2);\n"
         "                for(o = Y(i)-1; o<Y(j); ++o)\n"
         "                    puts(l[o]);\n"
         "                B;\n"
         "\n"
         "            A 'A':\n"
         "                y = r++;\n"
         "                strcpy(l[y], a+2);\n"
         "                x = c[y] = strlen(a+2);\n"
         "                ++x;\n"
         "                ++y;\n"
         "                B;\n"
         "\n"
         "            A 'i':\n"
         "                D();\n"
         "                --y;\n"
         "                x=X(0);\n"
         "                // Commands i and r are very similar -> fall through\n"
         "                // from i to r after moving rows down and setting\n"
         "                // position at end of line:\n"
         "\n"
         "            A 'r':\n"
         "                strcpy(*L+x-1, a+2);\n"
         "                *C = strlen(*L);\n"
         "                x = 1;\n"
         "                ++y > r && ++r;\n"
         "                B;\n"
         "\n"
         "            A 'I':\n"
         "                o = strlen(a+2);\n"
         "                memmove(*L+x+o-1, *L+x-1, *C-x+1);\n"
         "                *C += o;\n"
         "                memcpy(*L+x-1, a+2, o);\n"
         "                x += o;\n"
         "                B;\n"
         "\n"
         "            A 'd':\n"
         "                **L ? **L = *C = 0, x = 1 : U();\n"
         "                y = y>r ? r : y;\n"
         "                B;\n"
         "\n"
         "            A 'j':\n"
         "                y<r && U();\n"
         "        }\n"
         "    }\n"
         "}\n";);
}

สิ่งนี้ผลิต

main(){printf("Hello, World!");}
#define max(x,y)x>y?x:y
#define I(x)scanf("%d",&x)
a;b;main(){I(a);I(b);printf("\" max \": %d\n",max(a,b));}
x[10];*c;i;main(){int _e;for(;scanf("%d",&x)>0&&++_e;);for(c=x+_e;c-->x;i=100/ *x,printf("%d ",i- --_e));}
#define P printf(
#define A case
#define B break
#define L(i,e,t,f,s)for(o=i;o e;){strcpy(l[o t],l[o f]);c[o t]=c[s o];}
#define R(m,o){return b<1|b>m?m o:b;}
#define N(f)sscanf(f,"%d,%d",&i,&j)||sscanf(f,",%d",&j)
r,i,j,o,z,c[999],*C,x=1,y=1;char a[999],l[999][999],(*L)[999];D(){L(r,>y,,-1,--)r++?strcpy(l[o],l[o-1]+--x),c[o-1]=x,l[o-1][x]=0:0;c[y++]=strlen(l[o]);x=1;}U(){strcat(*L,l[y]);*C=strlen(*L);L(y+1,<r,-1,,++)--r;*l[r]=c[r]=0;}X(b)R(c[y-1],+1)Y(b)R(r,)main(){for(;;){z=i=y;L=l+--z;C=c+z;j=x;!r||y/r&&x>*C?P"end> "):P"%d,%d> ",y,x);scanf("%[^\n]%*c",a)?a[2]*=!!a[1],N(a)?y=Y(i+(i<0|*a=='+')*y),x=X(j+(j<0||strchr(a+1,'+'))*x):0:(*a=D(),scanf("%*c"));switch(*a){A'e':y=r;x=c[r-1]+1;B;A'b':y=1;x=1;B;A'L':for(o=y-4;++o<y+2;)o<0^o<r&&P"%c%s\n",o^z?' ' :'>',l[o]);for(o=x+1;--o;)P" ");P"^\n");B;A'l':puts(*L);B;A'p':i=1;j=0;N(a+2);for(o=Y(i)-1;o<Y(j);++o)puts(l[o]);B;A'A':y=r++;strcpy(l[y],a+2);x=c[y]=strlen(a+2);++x;++y;B;A'i':D();--y;x=X(0);A'r':strcpy(*L+x-1,a+2);*C=strlen(*L);x=1;++y>r&&++r;B;A'I':o=strlen(a+2);memmove(*L+x+o-1,*L+x-1,*C-x+1);*C+=o;memcpy(*L+x-1,a+2,o);x+=o;B;A'd':**L?**L=*C=0,x=1:U();y=y>r?r:y;B;A'j':y<r&&U();}}}

การ จำกัด

การแบ่งคำจำกัดความเช่น

#define A (x)

โดยการลบช่องว่างที่แยกชื่อออกจากการขยายให้

#define A(x)

ด้วยความหมายที่แตกต่างอย่างสิ้นเชิง กรณีนี้หายไปจากชุดทดสอบดังนั้นฉันจะไม่พูดกับมัน

ฉันสงสัยว่าฉันอาจสามารถสร้างเวอร์ชันที่สั้นกว่าด้วยการแปลงหลายตำแหน่งแบบแทนที่ได้ - ฉันอาจลองใช้ในสัปดาห์หน้า


คุณสามารถบันทึกหนึ่งไบต์โดยการเอา=ในตอนท้ายของคำนิยามของOและเปลี่ยนพื้นที่ที่เป็นไปตามแต่ละสายไปเป็นO =
Zacharý

นี่เป็นสิ่งที่ยอดเยี่ยม;) เกี่ยวกับ "ข้อ จำกัด " ดูความคิดเห็นของฉันที่มีต่อคำถามด้วยตนเอง - การตรวจสอบสิ่งนี้จะเพิ่มความซับซ้อนมากเกินไป
เฟลิกซ์ Palmen

@ Zachary - ขอบคุณที่ฉันลืมเมื่อฉันเปลี่ยนรหัสทั่วไปเป็นเฉพาะ ASCII ที่O'\\'และO' 'ทั้งสองได้รับช่องว่าง
Toby Speight


2

C,  705   663  640 ไบต์

ขอบคุณ @ Zacharýสำหรับการเล่นกอล์ฟ 40 ไบต์และขอบคุณ @Nahuel Fouilleul สำหรับการเล่นกอล์ฟ 23 ไบต์!

#define A(x)(x>47&x<58|x>64&x<91|x>96&x<123)
#define K if(*C==47&(C[1]==47|p==47)){if(p==47)--G;for(c=1;c;*C++-92||c++)*C-10||--c;if(d)p=*G++=10,--d;
#define D if(!d&*C==35){d=1;if(p&p-10)p=*G++=10;}
#define S K}if((A(p)&A(*C))|(p==*C&l==43|p==45)|p==47&*C==42|p==95&(A(*C)|*C==95)|*C==95&(A(p)|p==95))p=*G++=32;}
#define W*C<33|*C==92
#define F{for(;W;C++)
c,d,e,p,l;g(char*C,char*G)F;for(;*C;*C>32&&*C-34&&*C-39&&(p=*G++=*C),*C-34&&*C-39&&C++){l=e=0;if(*C==34)l=34;if(*C==39)l=39;if(l)for(*G++=l,p=*G++=*++C;*C++-l|e%2;e=*(C-1)-92?0:e+1)p=*G++=*C;K}D if(d){if(W)F{*C-92||++d;*C-10||--d;if(!d){p=*G++=10;goto E;}}S}else{if(W)F;S}E:D}*G=0;}

ลองออนไลน์!


สามารถfor(;W;C++){}กลายเป็นfor(;W;C++);?
Zacharý

@ Zacharýที่ไม่เคยถาม เป็นเครื่องมือสำหรับขั้นตอนสุดท้าย: ลบช่องว่างที่ซ้ำซ้อนและความคิดเห็นออก
Felix Palmen

ฉันอ้างถึงรหัสของเขาไม่ใช่ความท้าทาย
Zacharý

@ Zachary ฮ่าฮ่าฉันเห็น ... แปลกเมื่อรหัสและการป้อนข้อมูลเป็นภาษาเดียวกัน;)
เฟลิกซ์ Palmen

จะใช้งานได้ 665 ไบต์หรือไม่ goo.gl/E6tk8V
Zacharý

2

Perl 5, 250 + 3 (-00n) , 167 + 1 (-p) ไบต์

$_.=<>while s/\\
//;s,(//.*)|(("|')(\\.|.)*?\3)|/?[^"'/]+,$1|$2?$2:$&=~s@(\S?)\K\s+(?=(.?))@"$1$2"=~/\w\w|\+\+|--|\/\*/&&$"@ger,ge;$d++&&$l+/^#/&&s/^/
/,$l=/^#/m if/./

ลองออนไลน์


ใช่ฉันเพิ่งใส่โซลูชันที่ไม่เหมาะสม ฉันเพิ่งเพิ่มลิงค์ tio ฉันจะดูกอล์ฟเมื่อฉันมีเวลา
Nahuel Fouilleul

คำสั่ง preprocessor อยู่ในบรรทัดของตัวเองเมื่อวางไว้ก่อนรหัสเช่นเดียวกับในกรณีทดสอบ แต่ถ้าจำเป็นฉันจะเพิ่มการเปลี่ยนแปลง
Nahuel Fouilleul

1
คงที่ดูการปรับปรุง
Nahuel Fouilleul

0

Python 2 , 479 456 445 434 502 497 ไบต์

e=enumerate
import re
u=re.sub
def f(s):
 r=()
 for l in u(r'\\\n','',s).split('\n'):
	s=p=w=0;L=[]
	for i,c in e(l):
	 if(p<1)*'//'==l[i:i+2]:l=l[:i]
	 if c in"'\""and w%2<1:
		if p in(c,0):L+=[l[s:i+1]];s=i+1
		p=[0,c][p<1]
	 w=[0,w+1]['\\'==c]
	r+=L+[l[s:]],
 S=''
 for l in r:s=''.join([u('. .',R,u('. .',R,u('\s+',' ',x))).strip(),x][i%2]for i,x in e(l));S+=['%s','\n%s\n'][s[:1]=='#']%s
 print u('\n\n','\n',S).strip()
def R(m):g=m.group(0);f=g[::2];return[f,g][f.isalnum()or f in'++ -- /*']

ลองออนไลน์!

แก้ไข: คงที่จะรวม- -, + +และ/ *

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.