The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 3.03 on page 63
Write a function expand(s1,s2) that expands shorthand notations like a-z in the string s1 into the equivalent complete list abc...xyz in s2 . Allow for letters of either case and digits, and be prepared to handle cases like a-b-c and a-z0-9 and -a-z . Arrange that a leading or trailing - is taken literally.
Solution by Paul Griffiths
/* EX3_3.C ======= Suggested solution to Exercise 3-3 */ #include <stdio.h> #include <string.h> void expand(char * s1, char * s2); int main(void) { char *s[] = { "a-z-", "z-a-", "-1-6-", "a-ee-a", "a-R-L", "1-9-1", "5-5", NULL }; char result[100]; int i = 0; while ( s[i] ) { /* Expand and print the next string in our array s[] */ expand(result, s[i]); printf("Unexpanded: %s\n", s[i]); printf("Expanded : %s\n", result); ++i; } return 0; } /* Copies string s2 to s1, expanding ranges such as 'a-z' and '8-3' */ void expand(char * s1, char * s2) { static char upper_alph[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char lower_alph[27] = "abcdefghijklmnopqrstuvwxyz"; static char digits[11] = "0123456789"; char * start, * end, * p; int i = 0; int j = 0; /* Loop through characters in s2 */ while ( s2[i] ) { switch( s2[i] ) { case '-': if ( i == 0 || s2[i+1] == '\0' ) { /* '-' is leading or trailing, so just copy it */ s1[j++] = '-'; ++i; break; } else { /* We have a "range" to extrapolate. Test whether the two operands are part of the same range. If so, store pointers to the first and last characters in the range in start and end, respectively. If not, output and error message and skip this range. */ if ( (start = strchr(upper_alph, s2[i-1])) && (end = strchr(upper_alph, s2[i+1])) ) ; else if ( (start = strchr(lower_alph, s2[i-1])) && (end = strchr(lower_alph, s2[i+1])) ) ; else if ( (start = strchr(digits, s2[i-1])) && (end = strchr(digits, s2[i+1])) ) ; else { /* We have mismatched operands in the range, such as 'a-R', or '3-X', so output an error message, and just copy the range expression. */ fprintf(stderr, "EX3_3: Mismatched operands '%c-%c'\n", s2[i-1], s2[i+1]); s1[j++] = s2[i-1]; s1[j++] = s2[i++]; break; } /* Expand the range */ p = start; while ( p != end ) { s1[j++] = *p; if ( end > start ) ++p; else --p; } s1[j++] = *p; i += 2; } break; default: if ( s2[i+1] == '-' && s2[i+2] != '\0' ) { /* This character is the first operand in a range, so just skip it - the range will be processed in the next iteration of the loop. */ ++i; } else { /* Just a normal character, so copy it */ s1[j++] = s2[i++]; } break; } } s1[j] = s2[i]; /* Don't forget the null character */ }
{{Solution by Dawood Vora}}
/* EX3_3.C ======= 2nd Alternative solution to Exercise 3-3 */ #include <stdio.h> #include <ctype.h> #define INPUT 100 #define OUTPUT 500 #define STR_SIZE 30 #define DASH '-' int getinp(char []); void explow(int, int); char store[STR_SIZE]; int main () { char s[INPUT], t[OUTPUT]; int i,j,prv,nxt; for(i = 0; i < INPUT; i++) /* To flush input string */ s[i] = 0; for(i = 0; i < OUTPUT; i++) /* To flush output string */ t[i] = 0; j = prv = nxt = 0; if (getinp(s)) { for(i=0; s[i] == DASH;i++) /* Fill input with leading '-', if there is any */ t[i] = s[i]; j = i; while (s[i] != '\0') { if (s[i] != DASH) t[j++] = s[i++]; else if (s[i] == DASH) { prv = s[i-1], nxt = s[i+1]; if ((islower(prv) && islower(nxt)) || (isupper(prv) && isupper(nxt)) || (isdigit(prv) && isdigit(nxt))) { explow(prv,nxt); prv = nxt = 0; t[j] = '\0'; strcat(t,store); j = strlen(t); i++; } else t[j++] = s[i++]; } } printf("%s\n",t); } else printf("INPUT MISSING !!!!\n"); return 0; } /*-------------------------------------------------------------------------------------------*/ int getinp(char ip[]) /* function is ready */ { int i,c; i = 0; while (c = getchar()) { if (isalnum(c) || c == DASH) /* Get all alpha numeric and '-' into input string */ ip[i] = c; else switch (c) { /* ignore all irrelevant blank spaces */ case '\t': case '\v': case '\b': case '\r': case '\f': case '\\': case '\'': case '\"': break; case '\n': case EOF: /* Signal to mark end of input */ ip[i] = '\0'; break; default: break; } if (ip[i++] == '\0') break; } return i-1; /* for zero input, it will return zero */ } /*--------------------------------------------------------------------------------------------*/ void explow(int a, int z) { int i,j; extern char store[]; for(i = 0; i < STR_SIZE; i++) /*flush the array */ store[i] = 0; i = 0; if (a < z){ for (i = 0; (a+=1) < z; i++) store[i] = a; } else if (a > z) { for (i = 0; (a-=1)>z;i++){ store[i] = a; } } return ; }
Pilcrow 20:33, 14 September 2011 (UTC)
#include <stdio.h> #include "pilcrow.h" /* for getline */ #define MAXLINE 1024 #define UP(N) ((N) >= 'A' && (N) <= 'Z') #define LO(N) ((N) >= 'a' && (N) <= 'z') #define NU(N) ((N) >= '0' && (N) <= '9') #define AN(N) (UP(N) || LO(N) || NU(N)) int expand(char s1[], char s2[], int sz) { int i, j, temp; j=0; for(i = 0; s1[i] != '\0'; i++) { if(j >= sz) return 0; /* buffer overflow */ if(i==0 || s1[i] != '-') { /* first character or not '-'*/ s2[j++] = s1[i]; continue; } if(s1[i] == '-' && (!AN(s1[i-1]) || !AN(s1[i+1]))) { /* leading, trailing, isolated '-' */ s2[j++] = s1[i]; continue; } if(s1[i] == '-' && ( (UP(s1[i-1]) && UP(s1[i+1]) && s1[i-1] < s1[i+1]-1) || (LO(s1[i-1]) && LO(s1[i+1]) && s1[i-1] < s1[i+1]-1) || (NU(s1[i-1]) && NU(s1[i+1]) && s1[i-1] < s1[i+1]-1))) { temp = s1[i-1]+1; while (temp < s1[i+1]) { s2[j++] = temp++; } continue; } s2[j++] = s1[i]; /* didn't hit any 'continue's */ } s2[j] = '\0'; return 1; } int main(void) { char in[MAXLINE], out[MAXLINE]; while(getline(in,MAXLINE-1) > 1) { if(expand(in,out,MAXLINE-1)) printf("%s",out); else printf("buffer overflow\n"); } return 0; }










