Search code examples
ccs50caesar-cipher

How do I change each char in a string but not change punctuations in C?


I have an assignment to create a program that converts each character in a string by a set number entered at the command line. Example: if the user enters 1 at the command line then enters abc, def then the program should convert the string to bcd, efg.

I've written the program but I can't figure out how to get the program to not convert the punctuation characters.

The program currently converts abc, def and prints bcdefg. It needs to print bcd, efg and include the punctuation characters without converting them.

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

int main(int argc, string argv[]) //user enter number at cmd prompt

{
    string key = argv[1]; //store user entered number
    int k = atoi(argv[1]); //only accept consecutive digits
    if (argc != 2 || k == 0) 
    {    
        printf("Usage: ./caesar key\n"); /*show error if user enters non-consecutive digits*/
        return 1;
    }
    string original = get_string("Plaintext: "); /* prompt user for message to spin*/

    for (int i = 0, n = strlen(original); i < n; i++)  /* get string length and loop char change*/            
        if (isalnum(original[i])) /* only convert alphanumeric character*/                    
            printf("%c", original[i] + k); /* print and convert character by number entered at prompt*/

    printf("\n");
    return 0;
}

Solution

  • You are only outputting the characters that your are transforming (those that are in the isalnum set). You need to also output the characters not transformed. For example:

        char cipher = original[i] ;
        if( isalnum( original[i] )
        {
            cipher += k ;
        }
    
        printf( "%c", cipher ) ;
    

    However the algorithm as described remains deeply flawed in several ways, but it is not clear whether it is the assignment that is flawed (in which case that is not your problem) or if your description of the assignment is inaccurate.

    A more practical solution might look like:

    #include <ctype.h>
    
    char caesar( char x, int key )
    {
        const char alphabet[] = {'a','b','c','d','e','f','g','h',
                                 'i','j','k','l','m','n','o','p',
                                 'q','r','s','t','u','v','w','x',
                                 'y','z',
                                 '0','1','2','3','4','5','6','7','8','9'};
    
        char cipher = x  ;
    
        for( int i = 0;
             cipher == x && i < sizeof( alphabet );
             i++ )
        {
            if( alphabet[i] == tolower( x ) )
            {
                cipher = alphabet[(i + key) % sizeof( alphabet )] ;
                if( isupper( x ) )
                {
                    cipher = toupper( cipher ) ;
                }
            }
        }
    
        return cipher ;
    }
    

    Then your output loop would be:

    for( int i = 0; original[i] != '\0' ); i++)
    {
        printf("%c", ceasar( original[i], k ) ) ;
    }