Jump to: navigation, search

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;
}
Personal tools
Personal tools
Tidy_icons
not logged in