【问题标题】:How to wrap around alphabetically z to a and Z to A after shifting each letter by a number of places?在将每个字母移动多个位置后,如何按字母顺序将 z 环绕到 a 和 Z 到 A?
【发布时间】:2020-07-13 12:21:54
【问题描述】:

我正在编写一个代码,其中我将每个字母移动一个位置,因此 (a) 变为 (b) 并且 (b) 变为 (c) 等等。到目前为止,我设法做到了,但我遇到了一个将大写字母 (Z) 环绕到 (A) 的问题。我似乎无法理解如何做到这一点的逻辑。 任何帮助,将不胜感激。 非常感谢。

#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");
}

【问题讨论】:

  • 你能把小写和大写分开处理吗?无论如何,请仔细考虑您的逻辑。 ((p[i] &gt; 'z') &amp;&amp; (p[i] &gt; 'Z')) - 其中一项测试必须是多余的,原因与(x &gt; 10) &amp;&amp; (x &gt; 20) 等同于仅检查x &gt; 20 相同。
  • 问题在于if 条件,它检查您是否超出了“z”或“Z”。您将不得不根据情况打破条件。对于与此类似的小案例:if( smallCase(p[i]) &amp; p[i]&gt;'z') p[i]='a')
  • char U[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; for (int n = 20; n &lt; 30; n++) putchar(U[n%26]);

标签: c cs50 caesar-cipher


【解决方案1】:

另一种更接近初始程序的方法就是替换

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

通过

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

避免重复几乎所有代码,因为在另一个答案中就是这种情况


而且我认为替换它更具可读性

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

通过

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

编译器用它的值替换'z' - 'a' + 1,表达式自己解释目标


最后,我认为这样做更清楚

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

并且无谓地删除增量

或者只有一行:

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

但这可能不太可读


除此之外

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

很贵,可以换成

putchar(p[i]);

【讨论】:

  • @Bryce 我编辑了我的答案以在一行中给出一个解决方案,请阅读它
  • 顺便说一句,您能否解释一下以下逻辑: p[i] -= 'z' - 'a' + 1;谢谢
  • @Bryce 'z' - 'a' + 1 是 26 的来源。如果你有'z'+1 回到'a',你必须删除'z' - 'a' + 1。当然,大写和'z' - 'a' + 1 == 'Z - 'A' + 1 是一样的,因为小写和大写的数量相同......幸运的是^^
  • @Bryce p[i] += ((p[i] == 'z') || (p[i] == 'Z')) ? 'a' - 'z' : 1; 是 all 的缩写,允许根据情况添加 -25 或 1。当然是 25 而不是 26,因为这不是在代码中的增量之后完成的
【解决方案2】:

您需要将增量/检查分成大写和小写块,因为尽管字符 a ... zA ... Z最有可能按顺序排列,但它们会不同 序列。

为您的循环做一些事情:

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

(另外,我假设在您的代码中,{ after p[i]++; 是一个错字 - 否则,您正在检查 每个字符,即使它不是字母。您的缩进表明这不是您想要的。)

【讨论】:

  • 您刚刚向我介绍了解决此问题的另一种方法!你是我的救星!非常感谢:)
猜你喜欢
  • 2016-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-10
  • 1970-01-01
  • 1970-01-01
  • 2016-04-25
相关资源
最近更新 更多