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;
}

Solution by Prabhat Pal June 25, 2013

#include<stdio.h>
#include<ctype.h>

void expand(char s1[], char s2[])
{
    int state=0;
	/*
	5 states 0...4.
	0 : waiting for the first input character
	1 : first input character is an alphabet, say 'a'
	2 : first input character is a digit, say 7
	3 : first two input characters are an alphabet and '-', ignoring any white spaces in between, e.g. a-
	4 : first two input characters are a digit and '-', ignoring any white spaces in between, e.g. 7-
	
	Jump between the states 1...4 as new characters are fetched in. Modify s2 accordingly.
	*/
    int i,j,k;
    int first;
    i=j=k=0;
    while(1)
    {
        k=0;
        switch(state)
        {
        case 0:
            if(isalpha(s1[i]))
            {
                s2[j++]=s1[i];
                first=s1[i]+1;
                state=1;
            }
            else if(s1[i]=='\0')
            {
                s2[j]='\0';
                return;
            }
            else if(isdigit(s1[i]))
            {
                state=2;
                s2[j++]=s1[i];
                first=s1[i]+1;
            }
            ++i;
            break;
        case 1:
            if(isalpha(s1[i]))
            {
                first=s1[i]+1;
                s2[j++]=s1[i];
            }
            else if(isdigit(s1[i]))
            {
                state=2;
                s2[j++]=s1[i];
                first=s1[i]+1;
            }
            else if(s1[i]=='\0')
            {
                s2[j]='\0';
                return;
            }
            else if(s1[i]=='-')
            {
                state=3;
            }
            ++i;
            break;
        case 2:
            if(isalpha(s1[i]))
            {
                state=1;
                s2[j++]=s1[i];
                first=s1[i]+1;
            }
            else if(isdigit(s1[i]))
            {
                s2[j++]=s1[i];
                first=s1[i]+1;
            }
            else if(s1[i]=='-')
            {
                state=4;
            }
            else if(s1[i]=='\0')
            {
                s2[j]='\0';
                return;
            }
            ++i;
            break;
        case 3:
            if((isalpha(s1[i])) && (s1[i]>=first))
            {
                k=0;
                while(first+k<=s1[i])
                {
                    s2[j++]=first+k;
                    ++k;
                }
                first=s1[i]+1;
                state=1;
            }
            else if((isalpha(s1[i])) && (s1[i]<first))
            {
                k=0;
                while(first+k<='z')
                {
                    s2[j++]=first+k;
                    ++k;
                }
                s2[j++]=s1[i];
                first=s1[i]+1;
                state=1;
            }
            else if(isdigit(s1[i]))
            {
                k=0;
                while(first+k<='z')
                {
                    s2[j++]=first+k;
                    ++k;
                }
                s2[j++]=s1[i];
                first=s1[i]+1;
                state=2;
            }
            else if(s1[i]=='\0')
            {
                k=0;
                while(first+k<='z')
                {
                    s2[j++]=first+k;
                    ++k;
                }
                s2[j]='\0';
                return;
            }
            ++i;
            break;
        case 4:
            if(isalpha(s1[i]))
            {
                state=1;
                while(first+k<='9')
                {
                    s2[j++]=first+k;
                    ++k;
                }
                s2[j++]=s1[i];
                first=s1[i]+1;
            }
            else if(isdigit(s1[i]) && s1[i]>=first)
            {
                state=2;
                while(first+k<=s1[i])
                {
                    s2[j++]=first+k;
                    ++k;
                }
                first=s1[i]+1;
            }
            else if(isdigit(s1[i]) && s1[i]<first)
            {
                state=2;
                while(first+k<=s1[i])
                {
                    s2[j++]=first+k;
                    ++k;
                }
                s2[j++]=s1[i];
                first=s1[i]+1;
            }
            else if(s1[i]=='\0')
            {
                s2[j]='\0';
                return;
            }
            ++i;
            break;
        }
    }
}

int main(void)
{
    char s1[60];
    scanf("%s",s1);
    char s2[400];
    expand(s1,s2);
    printf("s1=%s\ns2=%s",s1,s2);
    return 0;
}

/*
Sample input #0
				f-w
output
				s1=f-w
				s2=fghijklmnopqrstuvw
				
Sample input #1
				2-7
output
				s1=2-7
				s2=234567

Sample input #2
				a-b-c-f
output
				s1=a-b-c-f
				s2=abcdef

Sample input #3
				-a-b-c9-0-3b-s-
output	
				s1=-a-b-c9-0-3b-s-
				s2=abc90123bcdefghijklmnopqrstuvwxyz
				
Sample input #4
				a-0-6b--pq-w9-0-3
output
				s1=a-0-6b--pq-w9-0-3
				s2=abcdefghijklmnopqrstuvwxyz0123456bcdefghijklmnopqrstuvw90123
*/

Solution : User Name :Sammy void expand(char s1[],char s2[]) {

   int i,j=0;
   for(i=0;s1[i] != '\0';i++)
   {
       switch(s1[i])
       {
       case '-':
            if(i==0 || s1[i+1]=='\0')
            {
                s2[j++]=s1[i];
                break;
             }
          else
          {
              if(((s1[i-1] >= 'a' && s1[i-1] <= 'z') && (s1[i+1] >= 'a' && s1[i+1] <= 'z')) ||
                 ((s1[i-1] >= 'A' && s1[i-1] <= 'Z') && (s1[i+1] >= 'A' && s1[i+1] <= 'Z')) ||
                 ((s1[i-1] >= '0' && s1[i-1] <= '9') && (s1[i+1] >= '0' && s1[i+1] <= '9')))
              {
                  int k;
                  if(s1[i-1] < s1[i+1]) {for(k=s1[i-1]+1;k <= s1[i+1]-1;k++) s2[j++]=k;}
                  else if(s1[i-1] > s1[i+1])
                  {
                    for(k=s1[i-1]-1;k >= s1[i+1]+1;k--) s2[j++]=k;
                  }
                  else
                  {
                      i++;
                  }
              break;
              }
          }
          default : s2[j++]=s1[i];break;
   }
   }
   s2[j]='\0';

} //how will the input 5-5-5 can be handled ? will it output to "555" or "55" or "5" ?

Personal tools
Personal tools
Tidy_icons
not logged in