C ++用户输入限制,没有“goto”正确重试

时间:2015-10-27 01:52:43

标签: c++ validation iostream goto istream

我有以下代码:

qstn:
  cout << "Input customer's lastname: ";
  getline(cin, lname);

  if (lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ") != string::npos) {
      cout << "You can only input alpha here!\n";
      cin.clear();
      goto qstn;
  } else if (lname.empty()) {
      cout << "Please enter your firstname!\n";
      cin.clear();
      goto qstn;
  }

  int lnamel = lname.length();
  int strl = str.length();
  int is = 0;

  for (int i = 1; i < strl;) {
      i++;
      is++;

      if (lname[i] == lname[is] && lname[i] == ' ' || lname[0] == ' ') {
          cin.clear();
          cout << "Please input your lastname properly!\n";
          goto qstn;
      }
  }
  // next question here

我很难想到什么是避免这种情况的正确逻辑 goto声明,自从我上大学以来我一直在使用它,但有人在这里说 根本不使用它可能会破坏我的代码。

我尝试使用do while循环,但它不像goto那样流畅。

请帮忙!

5 个答案:

答案 0 :(得分:5)

这是我喜欢使用的成语:

int i;

if (std::cin >> prompt("enter an integer: ", i))
{
    std::cout << "Read user input: " << i << "\n";
} else {
    std::cout << "Input failed (too many attempts). Eof? " << std::boolalpha << std::cin.eof() << "\n";
}

这里,prompt是一个智能输入操纵器,负责处理解析错误或流故障并重试。

它非常通用,所以实际上做了很多事情,但你不需要指出所有选项。当操纵器插入流中时,它会转发到do_manip成员:

template <typename Char, typename CharT>
friend std::basic_istream<Char, CharT>& operator>>(std::basic_istream<Char, CharT>& is, checked_input<T, Prompter>& manip) {
    return manip.do_manip(is);
}

do_manip处理所有逻辑而没有任何goto s :):

std::istream& do_manip(std::istream& is) {
    auto attempt = [this] { return infinite() || retries_ > 0; };

    while (attempt()) {
        if (!infinite())
            retries_ -= 1;

        prompter_(out_);

        if (is >> value_) {
            if (!run_validators(out_))
                is.setstate(is.rdstate() | std::ios::failbit);
            else
                break;
        } else {
            out_.get() << format_error_ << "\n";
        }

        if (attempt()) {
            is.clear();
            if (flush_on_error_)
                is.ignore(1024, '\n');
        }
    }

    return is;
}

您可以看到在接受输入之前可以运行验证。

这是一个有点全面的演示:

<强> Live On Coliru

int main() {
    using namespace inputmagic;

    int i;

    if (std::cin >> prompt("enter an integer: ", i)
            .retries(3)
            .flush_on_error(false)
            .format_error("I couldn't read that (Numbers look like 123)")
            .output(std::cerr)
            .validate([](int v) { return v > 3 && v < 88; }, "value not in range (3,88)")
            .validate([](int v) { return 0 == v % 2; })
            .validate([](int v) { return v != 42; }, "The Answer Is Forbidden")
            .multiple_diagnostics())
    {
        std::cout << "Read user input: " << i << "\n";
    } else {
        std::cout << "Input failed (too many attempts). Eof? " << std::boolalpha << std::cin.eof() << "\n";
    }
}

你可以看到它只接受有效的整数

  • >&gt;&lt; 88,
  • 甚至是
  • 除了42(禁止的号码)

在后续重试中输入数字21,42和10时,您会得到: live

enter an integer: 21
Value not valid
enter an integer: 42
The Answer Is Forbidden
enter an integer: 10
Read user input: 10

但是,如果您一直输入1: live

enter an integer: 1
value not in range (3,88)
Value not valid
enter an integer: 1
value not in range (3,88)
Value not valid
enter an integer: 1
value not in range (3,88)
Value not valid
Input failed (too many attempts). Eof? false

或者如果您从单行文件中读取: live

enter an integer: value not in range (3,88)
Value not valid
enter an integer: I couldn't read that (Numbers look like 123)
enter an integer: I couldn't read that (Numbers look like 123)
Input failed (too many attempts). Eof? true

答案 1 :(得分:2)

使用功能:

bool getLastName(string & lname,
                 string & str)
{
    cout << "Input customer's lastname: ";
    getline(cin, lname);

    if (lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")
            != string::npos)
    {
        cout << "You can only input alpha here!\n";
        cin.clear();
        return false;
    }
    else if (lname.empty())
    {
        cout << "Please enter your firstname!\n";
        cin.clear();
        return false;
    }
    int lnamel = lname.length();
    int strl = str.length();
    int is = 0;
    for (int i = 1; i < strl;)
    {
        i++;
        is++;
        if (lname[i] == lname[is] && lname[i] == ' ' || lname[0] == ' ')
        {
            cin.clear();
            cout << "Please input your lastname properly!\n";
            return false;
        }
    }
    return true;
}

我在这里完成的所有工作都是用goto替换return false s。如果程序到达函数的末尾,return true。在while循环中调用函数:

while (!getLastName(lname, str))
{
    // do nothing
}

这不仅会破坏代码,而且会将其分解为漂亮,小巧,易于管理的部分。这称为procedural programming

答案 2 :(得分:0)

While循环看起来是你最好的选择。您可以使用continue关键字重做循环。

int incorrect = 0;
while(!incorrect) {
cout<<"Input customer's lastname: ";
        getline(cin,lname);

        if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
            {
            cout<<"You can only input alpha here!\n";
            cin.clear();
            continue;
            }
        else if(lname.empty())
        {
            cout<<"Please enter your firstname!\n";
            cin.clear();
            continue;
        }
        int lnamel=lname.length();
        int strl=str.length();
        int is=0;
        for(int i=1; i<strl;)
        {
           i++;
           is++;
           if(lname[i]==lname[is]&&lname[i]==' '||lname[0]==' ')
           {
               cin.clear();
               cout<<"Please input your lastname properly!\n";
               continue;
           }
           incorrect = 1;
        }

答案 3 :(得分:0)

你需要使用一些do while循环 例如:

qstn:
            cout<<"Input customer's lastname: ";
            getline(cin,lname);

            if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
                {
                cout<<"You can only input alpha here!\n";
                cin.clear();
                goto qstn;
                }
            else if(lname.empty())
            {
                cout<<"Please enter your firstname!\n";
                cin.clear();
                goto qstn;
            }

可以重写为:

int flag;
do{
    flag = 1;
    cout<<"Input customer's lastname: ";
    getline(cin,lname);
    if(lname.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
    {
        flag = 0;
        cout<<"You can only input alpha here!\n";
    }
    else if(lname.empty())
    {
        flag = 0;
        cout<<"Please enter your firstname!\n";
    }
    cin.clear();
} while( flag !=1 );

随意使用布尔类型标志,它并不重要

答案 4 :(得分:0)

在我看来,你的代码缺乏明确的目的。

您显然不希望输入的字符串包含前导空格,也不希望包含多个连续空格。除此之外,只接受字母字符。

如果用户确实输入了多个连续的空格,我可能会忽略除第一个之外的所有空格。我可能会编写类似这样的代码:

#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <sstream>

bool non_alpha(std::string const &s) {
    return !std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalpha(c) || std::isspace(c); });
}

std::string get_name(std::string const &prompt) {
    std::string result;
    std::string line;

    do {
        std::cout << prompt;
        std::getline(std::cin, line);
    } while (non_alpha(line));

    std::istringstream words(line);
    std::string word;
    while (words >> word)
        result += word + ' ';
    return result;
}

int main() {
    auto res = get_name("Please enter last name, alpha-only\n");
    if (res.empty())
        std::cout << "Oh well, maybe some other time";
    else
        std::cout << "Thanks Mr(s). " << res << "\n";
}

我很想考虑对非字母字符大致相同 - 而不是要求用户从头开始重新输入,假设这是一个错误而忽略它。