The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 1.21 on page 34
Write a program entab that replaces strings of blanks with the minimum number of tabs and blanks to achieve the same spacing. Use the same stops as for detab . When either a tab or a single blank would suffice to reach a tab stop, which should be given preference?
Category 0 Solution by Rick Dearman
Category 1 Solution by Stefan Farfeleder
Rick Dearman's Cat 0 solution:
/****************************************************** KnR 1-21 -------- Write a program "entab" which replaces strings of blanks with the minimum number of tabs and blanks to achieve the same spacing. Author: Rick Dearman email: rick@ricken.demon.co.uk ******************************************************/ #include <stdio.h> #define MAXLINE 1000 /* max input line size */ #define TAB2SPACE 4 /* 4 spaces to a tab */ char line[MAXLINE]; /*current input line*/ int getline(void); /* taken from the KnR book. */ int main() { int i,t; int spacecount,len; while (( len = getline()) > 0 ) { spacecount = 0; for( i=0; i < len; i++) { if(line[i] == ' ') spacecount++; /* increment counter for each space */ if(line[i] != ' ') spacecount = 0; /* reset counter */ if(spacecount == TAB2SPACE) /* Now we have enough spaces ** to replace them with a tab */ { /* Because we are removing 4 spaces and ** replacing them with 1 tab we move back ** three chars and replace the ' ' with a \t */ i -= 3; /* same as "i = i - 3" */ len -= 3; line[i] = '\t'; /* Now move all the char's to the right into the ** places we have removed. */ for(t=i+1;t<len;t++) line[t]=line[t+3]; /* Now set the counter back to zero and move the ** end of line back 3 spaces */ spacecount = 0; line[len] = '\0'; } } printf("%s", line); } return 0; } /* getline: specialized version */ int getline(void) { int c, i; extern char line[]; for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '\n'; ++i) line[i] = c; if(c == '\n') { line[i] = c; ++i; } line[i] = '\0'; return i; }
Stefan Farfeleder's Cat 1 solution:
/* 1-21.c */ #include <stdio.h> #define TABSTOP 4 int main(void) { size_t spaces = 0; int ch; size_t x = 0; /* position in the line */ size_t tabstop = TABSTOP; /* get this from the command-line * if you want to */ while ((ch = getchar()) != EOF) { if (ch == ' ') { spaces++; } else if (spaces == 0) /* no space, just printing */ { putchar(ch); x++; } else if (spaces == 1) /* just one space, never print a tab */ { putchar(' '); putchar(ch); x += 2; spaces = 0; } else { while (x / tabstop != (x + spaces) / tabstop) /* are the spaces reaching behind the next tabstop ? */ { putchar('\t'); x++; spaces--; while (x % tabstop != 0) { x++; spaces--; } } while (spaces > 0) /* the remaining ones are real space */ { putchar(' '); x++; spaces--; } putchar(ch); /* now print the non-space char */ x++; } if (ch == '\n') { x = 0; /* reset line position */ } } return 0; }
/*-------------------------------------------------*/ /* Another solution for review purpose */ #include <stdio.h> #define MAXCHAR 1024 #define TABSPACE 8 int gline_entab(char[],int); int CalcNextTabStop(int,int); int main(void) { int len,p; char s[MAXCHAR]; p = 0; len = 0; while ((len = gline_entab(s,MAXCHAR))>0) { printf("%s",s); /* the following code is only meant for debugging purpose */ while (s[p] != '\0') { if (s[p] == '\t') { putchar('\\'); putchar('t'); } else if (s[p] == '\n') { putchar('\\'); putchar('n'); } else if (s[p] == ' ') putchar('-'); else putchar(s[p]); p++; } putchar('\n'); p = 0; } return 0; } int gline_entab(char s[], int lim) { int i,j,k,c; int fspace,cspace; i=j=k=fspace=cspace=0; while (i<lim-1 && ((c = getchar())!= EOF) && c != '\n') { printf("i = %d\n",i); if (c == ' ') { if (fspace == 0) { //first occurence of ' ' fspace = i; cspace=1; k= CalcNextTabStop(j,TABSPACE); } else { //repeat occurence of ' ' if (j == k) { s[fspace]='\t'; i = fspace; fspace = 0; cspace = 0; } else cspace++; } } else { if (cspace>0) i = fspace; while (cspace>0) { s[i] = ' '; i++; cspace--; } s[i] = c; fspace = 0; } i++; j++; } if (c == '\n') { s[i] = c; i++; } s[i] = '\0'; return i; } int CalcNextTabStop(int p,int sz) { return (((p/sz)+1)*sz)-1; }
Well, another simpler solution similar to that one of exercise 20. Please, review it.
TheSunShadow
#include <stdio.h> #define TAB 5 // Number of spaces of one tab. main() { int c, i = 0, j; while((c = getchar()) != EOF){ if(c == ' '){ ++i; // This is a counter of white spaces. if((i % TAB) == 0) // Every group of a number of 'TAB' putchar('\t'); // spaces is replaced by a tab. } else{ for(j = 0; j < (i % TAB); ++j) // Every group smaller than putchar(' '); // 'TAB' spaces is untouched. putchar(c); // Well, there exist other characters but spaces. if(i != 0) // Once some text is found, the counter is reset. i = 0; } } }
Solution by Amarendra Godbole, using the IN and OUT macros introduced earlier.
#include <stdio.h> #define TABSTOP 4 #define IN 1 #define OUT 0 int main(void) { int spc, i, c, nspace; int state, ntab; state = OUT; nspace = 0; ntab = 0; spc = 0; while ((c = getchar()) != EOF) { if (c == ' ') { state = IN; nspace++; } else { if (state == IN) { if (nspace >= TABSTOP) { ntab = nspace / TABSTOP; spc = nspace % TABSTOP; for (i = 0; i < ntab; i++) putchar('\t'); for (i = 0; i < spc; i++) putchar(' '); } else { for (i = 0; i < nspace; i++) putchar(' '); } nspace = 0; putchar(c); state = OUT; } else { putchar(c); } } } return 0; }










