Как получить определенные значения из пользовательского ввода и игнорировать другие - PullRequest
0 голосов
/ 23 апреля 2019

Есть ли способ получить только цифры из этой строковой записи:

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*, ...)'|

1 Ответ

2 голосов
/ 24 апреля 2019

Я сделал небольшой пример, чтобы продемонстрировать несколько способов прочитать пример 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;
}

Выход:

Using scanf():
h8 f7
Got h8 -> f7
Using scanf():
f7 h8
Got f7 -> h8
Using operator>>():
h8 f7
Got h8 -> f7
Using std::getline():
f7 h8
Got f7 -> h8

Демонстрация в реальном времени на coliru

Все четыре альтернативы следуют основной идее - читать входные данные как символы и впоследствии преобразовывать их в соответствующий индекс в диапазоне [0, 63].

Хотя char может представлять символы, оно также является интегральным значением & ndash; в частности, наименьший доступный интегральный тип. В (C и) C ++ это не имеет значения. Символ '1' сохраняется как целочисленное значение 33 (при условии ASCII код)). '1', а также 33 представляют одно и то же значение. Следовательно, хорошо (и даже рекомендуется) использовать символьные константы для арифметических вычислений, если это уместно (как в rcToInt() в приведенном выше примере).

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

    • Программа форматирования начинается с пробела (), чтобы использовать дополнительно ожидающий пробел.
    • %c хранит один символ. Следовательно, необходимо указать аргумент char* (указывающий на достаточное хранилище).
    • Форматер завершается пробелом () для использования завершающего ENTER .
    • Возвращаемое значение scanf() проверяется, чтобы предоставить все 4 аргумента.
  2. if (scanf(" %1[a-h]%1[1-8] %1[a-h]%1[1-8] ", c0, r0, c1, r1) < 4) {

    • Программа форматирования начинается и заканчивается пробелом () для использования окружающего пробела (как в предыдущем примере).
    • %1[a-h] читает строку длиной 1, которая может состоять только из символов a, b, ..., h. Должно быть предусмотрено хранилище для дополнительного байта, поскольку этот форматтер всегда будет хранить дополнительный 0-терминатор (\0). Следовательно, в этом случае отклонения char c0[2], r0[2], c1[2], r1[2];.
    • %1[1-8] аналогично приведенному выше для символов 1, 2, ..., 8. Обратите внимание, что цифры читаются как символы.
  3. if (!(std::cin >> c0 >> r0 >> c1 >> r1)) {

    • Чтение четырех char переменных с помощью операторов потокового ввода.
      Для этого заголовок iostream предоставляет множество перегруженных operator>> с (например, std::istream& operator>>(std::istream&, char&)).
    • Пробелы (возникающие перед чтением c1) пропускаются по умолчанию: std::cin.
  4. if (!std::getline(std::cin, line) || line.size() < 5) {

    • Считайте целую строку в std::string (который соответствующим образом вырос).
    • Анализировать символы в этом std::string.

Комбинация из 3. и 4. будет означать чтение строки с std::getline(), перенос строки чтения в std::istringstream для анализа ее с помощью операторов входного потока.


Извините, если я поменял местами строки и столбцы в приведенном выше коде. Я не специалист по шахматам и не знаю обычных преобразований.

...