如何更好地检查两个 char 变量是否在某些值集中?

myn*_*dlo 41 c++

最近,我们的教授要求我们使用两个char变量(天)来接收用户的输入。

下面的代码可以很好地作为检查,以确保 Mo、Tu、We、Th、Fr、Sa、Su 是仅有的两个作为一对一起输入的字符。如果接收到其他任何内容作为输入,它将循环并要求用户提供有效输入。

输入应该不区分大小写,这意味着,例如,"mO"并且"tu"是可以接受的。似乎有很多重复正在发生。有没有办法清理这个?

cout << "Please enter the day of the week did you made the long distance call (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;

while ((dayOne != 'M' && dayOne != 'm' || dayTwo != 'O' && dayTwo != 'o') &&
       (dayOne != 'T' && dayOne != 't' || dayTwo != 'U' && dayTwo != 'u') &&
       (dayOne != 'W' && dayOne != 'w' || dayTwo != 'e' && dayTwo != 'E') &&
       (dayOne != 'T' && dayOne != 't' || dayOne != 'H' && dayTwo != 'h') &&
       (dayOne != 'F' && dayOne != 'f' || dayTwo != 'R' && dayTwo != 'r') &&
       (dayOne != 'S' && dayOne != 's' || dayTwo != 'A' && dayTwo != 'a') &&
       (dayOne != 'S' && dayOne != 's' || dayTwo != 'U' && dayTwo != 'u'))
{
    cin.clear();
    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    cout << endl << "You have entered an invalid day. Please re-enter a day in the correct format (Mo Tu We Th Fr Sa Su): ";
    cin >> dayOne >> dayTwo;
}
Run Code Online (Sandbox Code Playgroud)

cig*_*ien 41

您可以编写一个折叠表达式,将 2 个字符与一个字符串进行比较:

template<typename ...Days>
bool any_of(char a, char b, Days ...days)
{
    return (... || (a == days[0] && b == days[1]));
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

while (! any_of(std::tolower(dayOne), std::tolower(dayTwo), "mo", "tu", "we", "th", "fr", "sa", "su"))
    // keep asking for input
Run Code Online (Sandbox Code Playgroud)

这是一个演示

这应该满足使用 2 个char输入的要求。

  • 这是一个非常优雅的解决方案,但是如果我给一个新程序员一个作业,并且他们返回了一个 C++ 折叠表达式,我会假设他们从某个地方复制了代码。一般来说,此类作业的目的是了解基本控制流。 (16认同)
  • @mascoj 是的,但在这种情况下,我认为这不是一个好的任务。问题应该是这样的:基本控制流*是*最好的解决方案,如果这是学生应该学习的概念的话。至少,这样学生可以学到新的东西,这也是解决给定问题的更好方法:) (8认同)
  • 不确定折叠表达式是什么,但我绝对愿意做一些研究。谢谢你为我打开了新事物的大门。 (3认同)

ana*_*lyg 21

您通常先使用tolowertoupperchar变量转换为正确的大小写。我喜欢使用tolower- 它看起来稍微好一点。

dayOne = tolower(dayOne);
dayTwo = tolower(dayTwo);

while (
    (dayOne != 'm' || dayTwo != 'o') &&
    (dayOne != 't' || dayTwo != 'u') &&
    (dayOne != 'w' || dayTwo != 'e') &&
    (dayOne != 't' || dayTwo != 'h') &&
    (dayOne != 'f' || dayTwo != 'r') &&
    (dayOne != 's' || dayTwo != 'a') &&
    (dayOne != 's' || dayTwo != 'u'))
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

您可以通过memcmp一次比较两个字符来进一步更改它,但我不确定它会简化代码。

  • 除非您已将两个字符组装成一个字符串,否则使用“memcmp”将调用未定义的行为,如果您已将它们组装成一个字符串,则最好进行字符串比较。 (4认同)

crs*_*rsn 13

另一种可能值得一提的方法是组织您的数据,以便您可以对它使用 std 函数 ( std::find)

// Example program
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>

int main()
{
    const std::vector<std::string> days = {
        "mo", "tu", "we", "th", "fr", "sa", "su"
    };

    bool found = false;

    while (found == false) {
        char dayOne, dayTwo;
        std::cout << "Please enter the first letter of the day" << std::endl;
        std::cin >> dayOne;
        std::cout << "Please enter the second letter of the day" << std::endl;
        std::cin >> dayTwo;

        std::string fullDay;
        fullDay += std::tolower(dayOne);
        fullDay += std::tolower(dayTwo);

        found = std::find(days.begin(), days.end(), fullDay) != days.end();
        std::cout << (found ? "correct day " : "invalid day, please try again ")
                  << fullDay
                  << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里运行

  • 感谢您的回复,但不幸的是,我们尚未在课程中介绍向量。然而,每次我用 google 搜索 CPP 相关的内容时,我都会看到向量,所以我将开始查找它们的用途! (4认同)
  • 动态分配的 std::vector 对于这种情况来说是多余的,因为您已经提前知道大小并且不再向其中添加任何项目。 (3认同)

Har*_*ngh 8

怎么样

switch (256 * tolower(dayOne) + tolower(dayTwo))
{
    case 256 * 'm' + 'o':
        // Monday
    case 256 * 't' + 'u':
        // Tuesday
}
Run Code Online (Sandbox Code Playgroud)

等等?

  • 对于任何想知道这是如何工作的人来说,它的作用是使用底层 ASCII 表示将每个两个“char”字符串转换为单个“int”;第一个字符左移 8 个空格,第二个字符不左移。这有效地将字符串转换为“int”,允许它们在“switch”语句中使用。 (5认同)
  • @JustinTime-ReinstateMonica 或者你可以说这只是 `dayOne &lt;&lt; 8 | 第二天`:] (2认同)
  • @PeterCordes - 是的,这就是导致我开始使用 Rust 的原因。我宁愿对抗借用检查器,也不愿对抗 C/C++ 中疯狂的整数规则。 (2认同)

Pau*_*ans 6

不知道您是否使用/允许使用正则表达式,但我会这样解决:

bool isDayOfTheWeek(char a, char b)
{
    std::string day({a, b});
    std::regex pattern("Mo|Tu|We|Th|Fr|Sa|Su", std::regex_constants::icase);
    return std::regex_search(day, pattern);
}
Run Code Online (Sandbox Code Playgroud)

然后简单地:

cout << "Please enter the day of the week did you made the long distance call (Mo Tu We Th Fr Sa Su): ";
cin >> dayOne >> dayTwo;

while (!isDayOfTheWeek(dayOne, dayTwo))
{
    cin.clear();
    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    cout << endl << "You have entered an invalid day. Please re-enter a day in the correct format (Mo Tu We Th Fr Sa Su): ";
    cin >> dayOne >> dayTwo;
}
Run Code Online (Sandbox Code Playgroud)

  • 把火箭筒收起来;这只是一只苍蝇! (10认同)
  • @PaulEvans 我真的很喜欢它,因为我发现它非常可读。但我不确定教授想要这个!:) (3认同)