如何从用户输入中获取某些值并忽略其他值

How to get certain values from user input and ignore others

有没有办法只从这个字符串输入中获取数字:

h8 f7

如果尝试过 fscanf。但是,可能我用错了。

int positionOfTheKnight = 0, finalDestination = 0;

fscanf("%*s%d %*s%d", &positionOfTheKnight, &finalDestination);

cout << positionOfTheKnight << " " << finalDestination;

显示以下错误:

cpp|11|error: cannot convert 'const char*' to 'FILE* {aka _iobuf*}' for argument '1' to 'int fscanf(FILE*, const char*, ...)'|

我做了一个小样本来演示多种读取OP示例的方法:

#include <cstdio>
#include <iostream>
#include <string>

int rcToInt(char c, char r)
{
  if (c < 'a' || c > 'h' || r < '1' || r > '8') {
    std::cerr << "Wrong input!\n";
    return -1;
  }
  return (c - 'a') * 8 + (r - '1'); // convert characters to index
}

int main()
{
  { // using scanf
    std::cout << "Using scanf():\n";
    char r0, c0, r1, c1;
    if (scanf(" %c%c %c%c ", &c0, &r0, &c1, &r1) < 4) {
      std::cerr << "Reading move with scanf() failed!\n";
    } else {
      const int pos0 = rcToInt(c0, r0), pos1 = rcToInt(c1, r1);
      if (pos0 >= 0 && pos1 >= 0) {
        std::cout << "Got " << c0 << r0 << " -> " << c1 << r1 << '\n';
      }
    }
  }
  { // Yet another way to use scanf():
    std::cout << "Using scanf():\n";
    char c0[2], r0[2], c1[2], r1[2];
    if (scanf("%1[a-h]%1[1-8] %1[a-h]%1[1-8] ", c0, r0, c1, r1) < 4) {
      std::cerr << "Reading move with scanf() failed!\n";
    } else {
      const int pos0 = rcToInt(*c0, *r0), pos1 = rcToInt(*c1, *r1);
      if (pos0 >= 0 && pos1 >= 0) {
        std::cout << "Got " << c0 << r0 << " -> " << c1 << r1 << '\n';
      }
    }
  }
  { // using std::cin
    std::cout << "Using operator>>():\n";
    char r0, c0, r1, c1;
    if (!(std::cin >> c0 >> r0 >> c1 >> r1)) {
      std::cerr << "Reading move with operator>>() failed!\n";
    } else {
      const int pos0 = rcToInt(c0, r0), pos1 = rcToInt(c1, r1);
      if (pos0 >= 0 && pos1 >= 0) {
        std::cout << "Got " << c0 << r0 << " -> " << c1 << r1 << '\n';
      }
    }
  }
  // There is still the [ENTER] in input queue which must be consumed:
  std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  // ...before proceeding
  { // using std::cin
    std::cout << "Using std::getline():\n";
    std::string line;
    if (!std::getline(std::cin, line) || line.size() < 5) {
      std::cerr << "Reading move with std::getline() failed!\n";
    } else {
      const char c0 = line[0], r0 = line[1], c1 = line[3], r1 = line[4];
      const int pos0 = rcToInt(c0, r0), pos1 = rcToInt(c1, r1);
      if (pos0 >= 0 && pos1 >= 0) {
        std::cout << "Got " << c0 << r0 << " -> " << c1 << r1 << '\n';
      }
    }
  }
  // done
  return 0;
}

输出:

使用 scanf():
h8 f7
得到 h8 -> f7
使用 scanf():
f7 h8
得到 f7 -> h8
使用运算符>>():
h8 f7
得到 h8 -> f7
使用 std::getline():
f7 h8
得到 f7 -> h8

Live Demo on coliru

所有四种方案都遵循将输入读取为字符的基本思想,然后将它们转换为 [0, 63] 范围内的相应索引。

虽然 char 可能代表字符,但它也是一个整数值——特别是最小的可用整数类型。在(C 和)C++ 中,这没有区别。字符 '1' 存储为整数值 33(假设 ASCII 代码))。 '1'33 代表相同的值。因此,在合适的情况下(如上例中的 rcToInt())使用字符常量进行算术计算是很好的(甚至推荐)。

  1. if (scanf(" %c%c %c%c ", &c0, &r0, &c1, &r1) < 4) {

    • Formatter 以 space (</code>) 开始,以消耗可选的未决白色 space.</li> <li><code>%c 存储一个字符。因此,必须提供 char* 参数(指向足够的存储空间)。
    • Formatter 以 space (</code>) 结尾以消耗终止 <kbd>ENTER</kbd>。</li> <li>检查 <code>scanf() 的 return 值以授予将分配所有 4 个参数。
  2. if (scanf(" %1[a-h]%1[1-8] %1[a-h]%1[1-8] ", c0, r0, c1, r1) < 4) {

    • Formatter 以 space (</code>) 开始和结束以消耗周围的白色 space(如上例所示)。</li> <li><code>%1[a-h] 读取长度为 1 的字符串,该字符串可能仅包含字符 ab、...、h。必须为额外字节提供存储空间,因为格式化程序将始终存储额外的 0 终止符 ([=26=])。因此,在这种情况下声明 char c0[2], r0[2], c1[2], r1[2];
    • %1[1-8] 类似于上面的字符 12、...、8。请注意,数字被读取为字符。
  3. if (!(std::cin >> c0 >> r0 >> c1 >> r1)) {

    • 使用流输入运算符读取四个 char 变量。
      iostream header 为此提供了多种重载的 operator>>(例如 std::istream& operator>>(std::istream&, char&))。
    • 白色space(发生在读取c1之前)被std::cin的默认设置跳过。
  4. if (!std::getline(std::cin, line) || line.size() < 5) {

    • 将一整行读入 std::string(适当增长)。
    • 分析std::string中的字符。

3. 和 4. 的组合是使用 std::getline() 读取一行,将读取的行包装在 std::istringstream 中以使用输入流运算符对其进行解析。


抱歉,如果我在上面的代码中交换了行和列。我不是国际象棋专家,也不知道通常的转换。