Jump to: navigation, search

The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 3.02 on page 60

Write a function escape(s,t) that converts characters like newline and tab into visible escape sequences like \n and \t as it copies the string t to s . Use a switch . Write a function for the other direction as well, converting escape sequences into the real characters.



Solution by Vidhan Gupta

/* Write a function escape(s,t) that converts characters like
newline and tab into visible escape sequences like \n and \t as it copies the string t to s.
Use a switch. Write a function for the other direction as well, converting esacpe sequences into the real characters. */

#include <stdio.h>

#define MAXIMUM 1000

int main()
{
    int c, i = 0;
    char s[MAXIMUM];
    while ((c = getchar()) != EOF)
    {
        switch (c)
        {
        case '\n':
            printf("\\n");
            break;
        case '\t':
            printf("\\t");
            break;
        default:
            putchar(c);
            break;
        }
        s[i] = c;
        i++;
    }
    printf("\n%s\n", s);
    return 0;
}


Solution by Paul Griffiths

/*
  
  EX3_2.C
  =======
  
  Suggested solution to Exercise 3-2

*/

#include <stdio.h>

void escape(char * s, char * t);
void unescape(char * s, char * t);

int main(void) {
    char text1[50] = "\aHello,\n\tWorld! Mistakee\b was \"Extra 'e'\"!\n";
    char text2[51];
    
    printf("Original string:\n%s\n", text1);
    
    escape(text2, text1);
    printf("Escaped string:\n%s\n", text2);
    
    unescape(text1, text2);
    printf("Unescaped string:\n%s\n", text1);
    
    return 0;
}


/*  Copies string t to string s, converting special
    characters into their appropriate escape sequences.
    The "complete set of escape sequences" found in
    K&R Chapter 2 is used, with the exception of:
    
    \? \' \ooo \xhh
    
    as these can be typed directly into the source code,
    (i.e. without using the escape sequences themselves)
    and translating them is therefore ambiguous.          */

void escape(char * s, char * t) {
    int i, j;
    i = j = 0;
    
    while ( t[i] ) {
        
        /*  Translate the special character, if we have one  */
        
        switch( t[i] ) {
        case '\n':
            s[j++] = '\\';
            s[j] = 'n';
            break;
            
        case '\t':
            s[j++] = '\\';
            s[j] = 't';
            break;
            
        case '\a':
            s[j++] = '\\';
            s[j] = 'a';
            break;
            
        case '\b':
            s[j++] = '\\';
            s[j] = 'b';
            break;
            
        case '\f':
            s[j++] = '\\';
            s[j] = 'f';
            break;
            
        case '\r':
            s[j++] = '\\';
            s[j] = 'r';
            break;
            
        case '\v':
            s[j++] = '\\';
            s[j] = 'v';
            break;
            
        case '\\':
            s[j++] = '\\';
            s[j] = '\\';
            break;
            
        case '\"':
            s[j++] = '\\';
            s[j] = '\"';
            break;
            
        default:
            
            /*  This is not a special character, so just copy it  */
            
            s[j] = t[i];
            break;
        }
        ++i;
        ++j;
    }
    s[j] = t[i];    /*  Don't forget the null character  */
}


/*  Copies string t to string s, converting escape sequences
    into their appropriate special characters. See the comment
    for escape() for remarks regarding which escape sequences
    are translated.                                             */

void unescape(char * s, char * t) {
    int i, j;
    i = j = 0;
    
    while ( t[i] ) {
        switch ( t[i] ) {
        case '\\':
            
            /*  We've found an escape sequence, so translate it  */
            
            switch( t[++i] ) {
            case 'n':
                s[j] = '\n';
                break;
                
            case 't':
                s[j] = '\t';
                break;
                
            case 'a':
                s[j] = '\a';
                break;
                
            case 'b':
                s[j] = '\b';
                break;
                
            case 'f':
                s[j] = '\f';
                break;
                
            case 'r':
                s[j] = '\r';
                break;
                
            case 'v':
                s[j] = '\v';
                break;
                
            case '\\':
                s[j] = '\\';
                break;
                
            case '\"':
                s[j] = '\"';
                break;
                
            default:
                
                /*  We don't translate this escape
                    sequence, so just copy it verbatim  */
                
                s[j++] = '\\';
                s[j] = t[i];
            }
            break;
            
        default:
            
            /*  Not an escape sequence, so just copy the character  */
            
            s[j] = t[i];
        }
        ++i;
        ++j;
    }
    s[j] = t[i];    /*  Don't forget the null character  */
}

Solution by Luke Panayi

My personal solution - only deals with \n and \t as the rest is just copy pasting the same concept. Hope I'm not this lonely for the rest of the book, it's only chapter 3 and most people seem to have vanished!

#include <stdio.h>
#define BUFFER 1000

void escape(char s[], char t[])	{

	int i, j=0; /*j is used as a counter to track how far ahead t is over s 
				when multiple characters need to be added in the place of one*/

	for (i=0; s[i-j] != '\0'; ++i)	{
		switch(s[i-j])	{
			case '\n':
				t[i] = '\\';
				t[++i] = 'n';
				++j;
				break;
			case '\t':
				t[i] = '\\';
				t[++i] = 't';
				++j;
				break;
			default:
				t[i] = s[i-j];
				break;
		}
	}

	t[i] = '\0';
}

void reverseEscape(char s[], char t[])	{

	int i, j=0;

	for (i=0; s[i+j] != '\0'; ++i)	{
		switch(s[i+j])	{
			case '\\':
				switch(s[i+j+1])	{
					case 'n':
						t[i] = '\n';
						++j;
						++i; //increment i to skip next character
						break;
					case 't':
						t[i] = '\t';
						++j;
						++i;
						break;					
				}
			default:
				t[i] = s[i+j];
				break;
		}
	}
	
	t[i] = '\0';
}

int main()	{

	int i, c;
	char s[BUFFER], t[BUFFER];

	for (i=0; i<BUFFER-1 && (c=getchar()) != EOF; ++i)
		s[i] = c;
	s[i] = '\0';

	escape(s,t);
	printf("%s\n", t);
	return 0;
}


Solution by Codybartfast (category 0)

The unescape function here can handle a string that ends with a single backslash. If an unescape function reads ahead for the character after a backslash, without checking if it is '\0', then the loop will continue indefinately beyond the end of the string. (Alternatively, strlen could be used to find the end of a string instead of checking for '\0').

enum bool { NO, YES };

void escape(char s[], char t[])
{
	int i = 0, j = 0;
	char c, e;

	while ((c = s[i++])) {
		if ((e = esc_char(c))) {
			t[j++] = '\\';
			t[j++] = e;
		} else {
			t[j++] = c;
		}
	}
	t[j] = '\0';
}

char esc_char(char c)
{
	switch (c) {
	case '\\':
		return '\\';
	case '\n':
		return 'n';
	case '\r':
		return 'r';
	case '\t':
		return 't';
	case '"':
		return '"';
	default:
		return '\0';
	}
}

void unescape(char s[], char t[])
{
	int i = 0, j = 0, esc_mode = NO;
	char c;

	while ((c = s[i++])) {
		if (esc_mode) {
			t[j++] = unesc_char(c);
			esc_mode = NO;
		} else if (c == '\\') {
			esc_mode = YES;
		} else {
			t[j++] = c;
		}
	}
	t[j] = '\0';
}

char unesc_char(char c)
{
	switch (c) {
	case 'n':
		return '\n';
	case 'r':
		return '\r';
	case 't':
		return '\t';
	case '\\':
	case '"':
	default:
		return c;
	}
}
Personal tools