Hintergrund
Für meine Code-Golf- Einsendungen in C benötige ich ein Verarbeitungswerkzeug. Wie in vielen anderen Sprachen ist Whitespace in C-Quellen meistens irrelevant (aber nicht immer!) - macht den Code dennoch für den Menschen viel verständlicher. Ein vollwertiges C-Programm, das häufig kein redundantes Leerzeichen enthält, ist kaum lesbar.
Aus diesem Grund schreibe ich meinen Code gerne in C für eine Code-Golf- Einreichung mit Leerzeichen und manchmal Kommentaren, damit das Programm beim Schreiben eine nachvollziehbare Struktur beibehält. Der letzte Schritt besteht darin, alle Kommentare und überflüssigen Leerzeichen zu entfernen. Dies ist eine mühsame und sinnlose Aufgabe, die eigentlich ein Praktikant eines Computerprogramms erledigen sollte .
Aufgabe
Schreiben Sie ein Programm oder eine Funktion, die Kommentare und überflüssige Leerzeichen aus einer C-Quelle "vor dem Golfen" gemäß den folgenden Regeln entfernt:
- Ein
\
(Backslash) als letztes Zeichen in einer Zeile ist eine Zeilenfortsetzung . Wenn Sie dies feststellen, müssen Sie die folgende Zeile als Teil derselben logischen Zeile behandeln (Sie können beispielsweise die\
und die folgenden\n
Zeilen (newline) vollständig entfernen, bevor Sie etwas anderes tun). - Kommentare verwenden nur das einzeilige Format, beginnend mit
//
. Um sie zu entfernen, ignorieren Sie den Rest der logischen Zeile, wo immer Sie//
außerhalb eines Zeichenfolgenliterals vorfinden (siehe unten). Leerzeichen sind (Leerzeichen),
\t
(Tabulator) und\n
(Zeilenvorschub, hier also das Ende einer logischen Zeile).Wenn Sie eine Folge von Leerzeichen finden, untersuchen Sie die Nicht-Leerzeichen-Zeichen, die sie umgeben. Wenn
- beide sind alphanumerisch oder unterstrichen (Range
[a-zA-Z0-9_]
) oder - beide sind
+
oder - beide sind
-
oder - das vorhergehende ist
/
und das folgende ist*
Ersetzen Sie dann die Sequenz durch ein einzelnes Leerzeichen (
).
Andernfalls beseitigen Sie die Reihenfolge vollständig.
Diese Regel hat einige Ausnahmen :
- Präprozessor-Direktiven müssen in Ihrer Ausgabe in eigenen Zeilen erscheinen. Eine Präprozessor-Direktive ist eine Zeile, die mit beginnt
#
. - In einem String-Literal oder Zeichen-Literal sollten Sie keine Leerzeichen entfernen. Jedes
"
(doppelte Anführungszeichen) /'
(einfache Anführungszeichen), dem keine ungerade Anzahl von umgekehrten Schrägstrichen (\
) vorangestellt ist, beginnt oder endet ein Zeichenkettenliteral / Zeichenliteral . Es ist garantiert, dass Zeichenketten- und Zeichenliterale in derselben Zeile enden, in der sie begonnen haben. Stringliterale und Zeichenliterale können nicht verschachtelt werden, so dass ein'
in einem Stringliteral , sowie ein"
in einem Zeichenliteral haben keine besondere Bedeutung.
- beide sind alphanumerisch oder unterstrichen (Range
E / A-Spezifikation
Eingabe und Ausgabe müssen entweder Zeichenfolgen (Strings) einschließlich Zeilenumbrüchen oder Arrays / Listen von Strings sein, die keine Zeilenumbrüche enthalten. Wenn Sie Arrays / Listen verwenden, stellt jedes Element eine Zeile dar, sodass die Zeilenumbrüche nach jedem Element implizit sind.
Sie können davon ausgehen, dass die Eingabe ein gültiger C-Programm-Quellcode ist. Dies bedeutet auch, dass es nur druckbare ASCII-Zeichen, Tabulatoren und Zeilenumbrüche enthält. Undefiniertes Verhalten bei fehlerhafter Eingabe ist zulässig.
Führende und nachfolgende Leerzeichen / Leerzeilen sind nicht erlaubt .
Testfälle
Eingang
main() { printf("Hello, World!"); // hi }
Ausgabe
main(){printf("Hello, World!");}
Eingang
#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)); }
Ausgabe
#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));}
Eingang
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)); }
Ausgabe
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));}
Eingang
x; #include <stdio.h> int main() { puts("hello // there"); }
Ausgabe
x; #include<stdio.h> int main(){puts("hello // there");}
Eingabe (ein Beispiel aus der Praxis)
// 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(); } } }
Ausgabe
#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();}}}
Dies ist Code-Golf , also gewinnt die kürzeste (in Bytes) gültige Antwort.