Reputation: 21
I have a QTableWidget where the user inputs complex numbers in various styles. For example, the complex number (-15 + 8.14i) can be written like:
-15 + 8.14i
-15+8.14j
-15 +j 8,14
-15+ i8,14
i can also be j! Both values can be big (they are saved as double) and also negative. They can be written with "," and "." (so 3.14 and 3,14 are ment to be equal). There should be an error message when the user enters the number incorrectly.
CKomplex fromString(QString str) { // ckomplex is my custom class for complex numbers
double numReal, numImag;
QString strNew = "";
// delete all spaces
for (int i= 0; i< str.length(); i++) {
if (!str[i].isSpace()) {
strNew += str[i];
}
}
QString part1 = "";
int index;
// get the first number
for (int i= 0; i < strNew.length(); i++) { // iterate string
if (strNew[i] != '+' && strNew[i] != '-') {
part1 += strNew[i];
} else { // e.g.: 5 + 3j -> the loop is at the "+"
if (i != 0) {
index = i; // save index at "+" to start for next number
break;
}
}
}
numReal = part1.toDouble();
QString part2 = "";
// get the second number
for (int i= index; i < strNew.length(); i++) {
if (strNew[i].isDigit() || strNew[i] == '+' || strNew[i] == '-' || strNew[i] == '.' || strNew[i] == ',') { // ignore j or i
part2 += strNew[i];
}
}
numImag = part2.toDouble();
return CKomplex(numReal, numImag);
}
This does work for basic input. But is not very fast or readable or useful. And it does cover just few possibilities of input (stuff like "-3 - 5,14" doesnt work). Is there an easier way to convert the string into a complex number without having so much loops and variables?
Upvotes: 0
Views: 120
Reputation: 11002
A single regular expression could parse each of the lines:
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
#include <regex>
#include <iostream>
#include <iomanip>
#include <exception>
class CKomplex {
public:
CKomplex(double numReal, double numImag) : numReal{numReal}, numImag{numImag} {}
double numReal;
double numImag;
};
auto input_text{
R"(-15 + 8.14i
-15+8.14j
-15 +j 8,14
-15+ i8,14
bad line here
+23.4-j24
-35+42.3j
+24i
+2.342j
+24.523-i 432,52
24.523-i 432,52
23.4-j24
35+42.3j
24i
2.342j)"};
CKomplex fromString(std::string str) {
double numReal{};
double numImag{};
std::regex r{R"(([+-]?) *([ij]?) *(\d+)[.,]?(\d*)([ij])?)"}; // 6 groups
std::istringstream iss(str);
auto it = std::sregex_iterator(str.begin(), str.end(), r);
auto end = std::sregex_iterator();
if(it == end || it->size() != 6)
throw std::runtime_error("Could not parse line containing the following text: " + str);
for(; it != end; ++it) {
auto match = *it;
auto sign = match[1].str();
auto iorj_pre = match[2].str();
auto decimal = match[3].str();
auto fraction = match[4].str();
auto iorj_post = match[5].str();
double val{sign == "-" ? -1.F : 1.F};
val *= std::stod(decimal + "." + fraction);
if(iorj_pre == "i" || iorj_pre == "j" || iorj_post == "i" || iorj_post == "j")
numImag += val;
else
numReal += val;
}
return{numReal,numImag};
}
std::ostream& operator<<(std::ostream& os, const CKomplex& complex_number)
{
os << std::showpos << "(" << complex_number.numReal << " " << complex_number.numImag << "i)";
return os;
}
int main()
{
std::istringstream input_stream{input_text};
for(std::string line{}; std::getline(input_stream, line);) {
try { std::cout << std::setw(20) << line << ": " << fromString(line) << '\n'; }
catch(std::exception& e) { std::cout << e.what() << '\n'; }
}
return 0;
}
Produces (live demo):
-15 + 8.14i: (-15 +8.14i)
-15+8.14j: (-15 +8.14i)
-15 +j 8,14: (-15 +8.14i)
-15+ i8,14: (-15 +8.14i)
Could not parse line containing the following text: bad line here
+23.4-j24: (+23.4 -24i)
-35+42.3j: (-35 +42.3i)
+24i: (+0 +24i)
+2.342j: (+0 +2.342i)
+24.523-i 432,52: (+24.523 -432.52i)
24.523-i 432,52: (+24.523 -432.52i)
23.4-j24: (+23.4 -24i)
35+42.3j: (+35 +42.3i)
24i: (+0 +24i)
2.342j: (+0 +2.342i)
Upvotes: 1