tło
Do przesłania kodu do golfa w C potrzebuję narzędzia do przetwarzania. Podobnie jak w wielu innych językach, białe znaki są przeważnie nieistotne w źródle C (ale nie zawsze!) - nadal sprawiają, że kod jest znacznie bardziej zrozumiały dla ludzi. W pełni golfowy program C, który nie zawiera ani jednej nadmiarowej białej spacji, często jest ledwo czytelny.
Dlatego lubię pisać mój kod w C dla kodu golfowego, w tym białych znaków i czasami komentarzy, więc program zachowuje zrozumiałą strukturę podczas pisania. Ostatnim krokiem jest usunięcie wszystkich komentarzy i zbędnych białych znaków. Jest to żmudne i bezmyślne zadanie, które naprawdę powinien wykonać stażysta programu komputerowego.
Zadanie
Napisz program lub funkcję, która eliminuje komentarze i zbędne białe znaki z jakiegoś „wstępnie golfowego” źródła C zgodnie z następującymi zasadami:
- A
\
(ukośnik odwrotny) jako ostatni znak w linii jest kontynuacją linii . Jeśli to znajdziesz, musisz traktować następujący wiersz jako część tego samego wiersza logicznego (możesz na przykład całkowicie usunąć\
następny i następujący\n
(nowy wiersz) przed zrobieniem czegoś innego) - Komentarze będą używać tylko formatu jednowierszowego, zaczynając od
//
. Tak, aby je usunąć, zignorować resztę logicznej linii gdziekolwiek spotkać//
poza ciągiem znaków (patrz poniżej). - Znaki białych znaków to
(spacja),
\t
(tab) i\n
(nowa linia, więc tutaj koniec linii logicznej). Gdy znajdziesz sekwencję białych znaków, sprawdź otaczające ją znaki niebiałe. Jeśli
- oba są alfanumeryczne lub podkreślone (zakres
[a-zA-Z0-9_]
) lub - oba są
+
lub - oba są
-
lub - poprzedni jest,
/
a następny jest*
następnie zastąp sekwencję pojedynczym znakiem spacji (
).
W przeciwnym razie całkowicie wyeliminuj sekwencję.
Ta reguła ma kilka wyjątków :
- Dyrektywy preprocesora muszą pojawiać się w osobnych wierszach na wydruku. Dyrektywa preprocesora to linia zaczynająca się od
#
. - Wewnątrz literału łańcuchowego lub literału znakowego nie należy usuwać żadnych białych znaków. Dowolny
"
(podwójny cudzysłów) /'
(pojedynczy cudzysłów), który nie jest poprzedzony nieparzystą liczbą odwrotnych ukośników (\
), rozpoczyna lub kończy literał łańcuchowy / literał znakowy . Masz gwarancję, że literały ciągów i znaków kończą się w tym samym wierszu, w którym zaczęły. literałów ciągów i literałów znakowych nie można zagnieżdżać, więc'
wewnątrz literału ciągowego , jak również"
wewnątrz literału znakowego , nie ma żadnego specjalnego znaczenia.
- oba są alfanumeryczne lub podkreślone (zakres
Specyfikacja we / wy
Dane wejściowe i wyjściowe muszą być albo ciągami znaków (ciągami znaków), w tym znakami nowej linii, albo tablicami / listami ciągów znaków, które nie zawierają znaków nowej linii. Jeśli zdecydujesz się użyć tablic / list, każdy element reprezentuje linię, więc nowe linie są ukryte po każdym elemencie.
Możesz założyć, że dane wejściowe są poprawnym kodem źródłowym programu C. Oznacza to również, że zawiera tylko drukowalne znaki ASCII, tabulatory i znaki nowej linii. Niezdefiniowane zachowanie na nieprawidłowo wprowadzonych danych jest dozwolone.
Wiodące i końcowe białe znaki / puste linie są niedozwolone .
Przypadki testowe
Wejście
main() { printf("Hello, World!"); // hi }
wynik
main(){printf("Hello, World!");}
Wejście
#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)); }
wynik
#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));}
Wejście
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)); }
wynik
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));}
Wejście
x; #include <stdio.h> int main() { puts("hello // there"); }
wynik
x; #include<stdio.h> int main(){puts("hello // there");}
wejście (przykład z prawdziwego świata)
// 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(); } } }
wynik
#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();}}}
To jest golf golfowy , więc wygrywa najkrótsza (w bajtach) poprawna odpowiedź.