How to wrap around alphabetically z to a and Z to A after shifting each letter by a number of places?

Viewed 457

I am working on a code in which I shift each letter by one place, so (a) becomes (b) and (b) becomes (c) and so on. So far I managed to do that, but I am confronting a problem wrapping around the capital letter (Z) to (A). I can't seem to get the logic how to do that. Any help would be appreciated. Thanks a lot.

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

int main(void)
{
    //prompt the user to type in a text.
    string p = get_string("plaintext: ");
    
    //create a variable to refer to the length of the string.
    int n = strlen(p);
    
    
    for (int i = 0; i < n; i++)
    {
        //check if all chars (i) in the string (p) are alphabetical then increment i by 1.
        if (isalpha(p[i]))
        p[i]++;

        {
            //check if i has gone beyond the letter (z) and (Z).
            if ((p[i] > 'z') && (p[i] > 'Z'))
            {
                //if so then subtract 26 letter after z or Z to get back to a or A.
                p[i] = p[i] - 26;
            }

        }
        printf("%c", p[i]);
    }
    printf("\n");
}
2 Answers

an other way closer to the initial program is just to replace

if ((p[i] > 'z') && (p[i] > 'Z'))

by

if ((p[i] == 'z'+1) || (p[i] == 'Z'+1))

that avoid to duplicate almost all the code as this is the case in the other answer


And I think it is more readable to replace

p[i] = p[i] - 26;

by

p[i] -= 'z' - 'a' + 1;

The compiler replace 'z' - 'a' + 1 by its value and the expression explain the goal by itself


And to finish I think it is more clear to do

if (isalpha(p[i]))
{
  if ((p[i] == 'z') || (p[i] == 'Z'))
    p[i] -= 'z' - 'a';
  else
    p[i] += 1;
}

and that remove an increment for nothing

or to have only one line :

if (isalpha(p[i]))
  p[i] += ((p[i] == 'z') || (p[i] == 'Z')) ? 'a' - 'z' : 1;

but this is less readable probably


Out of that

printf("%c", p[i]);

is expensive and can be replaced by

putchar(p[i]);

You need to separate your increments/checks into uppercase and lowercase blocks because, although the characters a ... z and A ... Z are most likely to be in sequence, they will be different sequences.

Something along these lines for your loop:

    for (int i = 0; i < n; i++) {
        //check if all chars (i) in the string (p) are alphabetical then increment i by 1.
        if (islower(p[i])) { // Lowercase letter check ...
            p[i]++;
            //check if i has gone beyond the letter (z).
            if (p[i] > 'z') {
                //if so then subtract 26 letter after z to get back to a.
                p[i] = p[i] - 26;
            }

        }
        else if (isupper(p[i])) { // Uppercase letter check ...
            p[i]++;
            //check if i has gone beyond the letter (Z).
            if (p[i] > 'Z') {
                //if so then subtract 26 letter after Z to get back to A.
                p[i] = p[i] - 26;
            }

        }
        printf("%c", p[i]);
    }

(Also, I'm assuming that, in your code, having the { after p[i]++; is a typo - otherwise, you're checking every character, even if it is not a letter. Your indentation suggests that this is not what you intend.)

Related