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.

#include <stdio.h>

#define LEN 1000

void expand(char s1[], char s2[]);

int main()
{
	char s1[] =
		"Lowercase: a-z\nUppercase: A-Z\nNumeric: 0-9\nAll: a-zA-Z0-9\nPre/post-fixes: -a-z A-Z-a\nRed herrings: a-b-c 0-z a-9 a-Z";
	char s2[LEN];

	expand(s1, s2);
	printf("%s", s2);
}

/* Only handles sequences in order! */
void expand(char s1[], char s2[])
{
	enum states { DEFAULT, LOWER, UPPER, NUMERIC };

	char c, c1, c2, k;
	int i, j;
	char begin, end;
	enum states state = DEFAULT;

	for (i = j = 0; (c = s1[i]) != '\0'; i++) {
		if (state == DEFAULT) {
			/* Hyphen triggers state transition if previous character valid */
			if (c == '-') {
				if (c1 >= 'a' && c1 <= 'z') {
					state = LOWER;
				} else if (c1 >= 'A' && c1 <= 'Z') {
					state = UPPER;
				} else if (c1 >= '0' && c1 <= '9') {
					state = NUMERIC;
				} // else state remains DEFAULT
			}
		} else {
			/* Execute state action if terminating character valid */
			if ((state == LOWER && c >= 'a' && c <= 'z') ||
			    (state == UPPER && c >= 'A' && c <= 'Z') ||
			    (state == NUMERIC && c >= '0' && c <= '9')) {
				/* Start at c2 + 1 as c2 already pushed before state transition 
				 * End at c - 1 as c will be pushed at the end of this loop */
				for (k = c2 + 1; k <= c - 1; k++) {
					s2[j++] = k;
				}
			} else {
				/* Terminating character invalid, ensure '-' is pushed */
				s2[j++] = '-';
			}
			state = DEFAULT;
		}

		if (state == DEFAULT) {
			s2[j++] = c;
		}
		c2 = c1;
		c1 = c;
	}
	s2[j] = '\0';
}