Я уже рекомендовал написать небольшой синтаксический анализатор (например, на основе синтаксической диаграммы, подобной показанной в 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 не указал, где следует принимать пробелы, а где нет.