Разбирать комплексное число из строки, учитывая синтаксические вариации - PullRequest
0 голосов
/ 29 января 2019

Я делаю консольное приложение, где я могу вводить комплексные числа.Все работает, но я хотел бы быть более гибким с форматированием ввода.Сейчас он принимает только + bi, я бы хотел сделать так, чтобы, если я просто ввел 3 или -2i, он все еще работал.

Complex console::parseComplex(std::string cmp) { 
    float a, b;
    char i;
    std::stringstream ss(cmp);
    if (ss >> a >> b >> i && i == 'i')
        return { a, b };
    else return { true };

Дело в том, что насколько я знаю, если ядобавьте следующее

    else if (ss >> a >> i && i == '\0')
        return { a, 0 };
    else if (ss >> b >> i && i == 'i')
        return { 0, i };

До моей последней строки это не будет работать, так как >> проходит через ss.В строке не будет пробелов.Я не уверен, как изменить его, не переписав ss (что, я полагаю, не самый лучший способ сделать это)

И я не уверен, как отфильтровать любые случайные символы, конвертируемые в целыеи отправить прочь, проверка на '\ 0' кажется неправильной.

Спасибо!

(Кстати, возврат {true} идет в m_fail для класса, который проверяется, это самый простой способ ошибкиЯ мог бы придумать, но если у вас есть какие-либо документы по этой теме, я хотел бы прочитать больше)

1 Ответ

0 голосов
/ 29 января 2019

Я уже рекомендовал написать небольшой синтаксический анализатор (например, на основе синтаксической диаграммы, подобной показанной в SO: Как перестроить строковое уравнение? ).

Далее я сделалболее простой подход, аналогичный тому, который использовался OP (и без создания схемы синтаксиса).

Т.е. оператор потока ввода для моего вспомогательного типа Complex пытается прочитать два числа.

Если сначалаза номером следует i, на самом деле это второе число, и ввод заканчивается.

Если за вторым номером не следует i, на самом деле это не второе, а отсутствует, и поток сбрасывается в положение перед.

Пример кода:

#include <cmath>
#include <iomanip>
#include <iostream>
#include <sstream>

struct Complex {
  float re, im;
};

std::istream& operator >> (std::istream &in, Complex &value)
{
  value.im = 0;
  // read 1st value
  if (!(in >> value.re)) return in; // ERROR!
  // check whether next char is 'i'
  char c; if (!(in >> c)) return in; // End of Input
  if (c == 'i') {
    value.im = value.re; value.re = 0.0;
    return in;
  }
  in.unget();
  // remember start of imaginary
  std::streampos pos = in.tellg();
  if (!(in >> value.im)) return in; // ERROR or end of input
  if (!(in >> c) || c != 'i') { // ERROR or premature end of input
    value.im = 0.0;
    in.clear();
    in.seekg(pos);
    return in;
  }
  return in;
}

std::ostream& operator << (std::ostream &out, const Complex &value)
{
  return out << value.re << (std::signbit(value.im) ? "" : "+") << value.im << 'i';
}

int main()
{
  // samples:
  std::string samples[] = {
    "1.23+45i",
    " 1.23 +45i",
    " 1.23E3 +45e-1i",
    "Completely wrong!",
    // multiple numbers in one line
    "1.23+45i 1.23 +45i 1.23E3 +45e-1i",
    "1.23 2.34-1i -2i"
  };
  int line = 1;
  for (const std::string &sample : samples) {
    std::cout << "Parse line " << line++ << " '" << sample << "':\n";
    std::istringstream in(sample);
    std::cout << "Got:";
    Complex value;
    while (in >> std::skipws >> value) std::cout << ' ' << value;
    std::cout << '\n'
      << "Stopped with "
      << (in.eof() ? "End of Input" : !in.good() ? "Error" : "???")
      << '\n';
  }
  return 0;
}

Скомпилировано и протестировано:

g++ (GCC) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Parse line 1 '1.23+45i':
Got: 1.23+45i
Stopped with End of Input
Parse line 2 ' 1.23 +45i':
Got: 1.23+45i
Stopped with End of Input
Parse line 3 ' 1.23E3 +45e-1i':
Got: 1230+4.5i
Stopped with End of Input
Parse line 4 'Completely wrong!':
Got:
Stopped with Error
Parse line 5 '1.23+45i 1.23 +45i 1.23E3 +45e-1i':
Got: 1.23+45i 1.23+45i 1230+4.5i
Stopped with End of Input
Parse line 6 '1.23 2.34-1i -2i':
Got: 1.23+0i 2.34-1i 0-2i
Stopped with End of Input

Живая демоверсия на coliru

Во время игры я все еще осознавал некоторые слабости, например, например, 1.23 + 45i, которые невозможно прочитать из-за пробела между + и 45.Таким образом, с еще большим количеством кода это можно улучшить наверняка.С другой стороны ... OP не указал, где следует принимать пробелы, а где нет.

...