如何从用户输入中获取数据?
How to get data from user input?
我有一个 QTableWidget,用户可以在其中输入各种样式的复数。
例如,复数 (-15 + 8.14i) 可以这样写:
-15 + 8.14i
-15+8.14j
-15 +j 8,14
-15+ i8,14
i也可以是j!
这两个值都可以很大(它们被保存为双精度值)也可以是负值。它们可以用“,”和“。”来书写。 (所以 3.14 和 3,14 是相等的)。当用户输入错误的数字时应该有一个错误信息。
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);
}
这对基本输入有效。但是不是很快或可读性或有用。它确实涵盖了很少的输入可能性(诸如“-3 - 5,14”之类的东西不起作用)。没有那么多循环和变量,有没有更简单的方法将字符串转换为复数?
一个 regular expression 可以解析每一行:
#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;
}
产生(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)
我有一个 QTableWidget,用户可以在其中输入各种样式的复数。 例如,复数 (-15 + 8.14i) 可以这样写:
-15 + 8.14i
-15+8.14j
-15 +j 8,14
-15+ i8,14
i也可以是j! 这两个值都可以很大(它们被保存为双精度值)也可以是负值。它们可以用“,”和“。”来书写。 (所以 3.14 和 3,14 是相等的)。当用户输入错误的数字时应该有一个错误信息。
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);
}
这对基本输入有效。但是不是很快或可读性或有用。它确实涵盖了很少的输入可能性(诸如“-3 - 5,14”之类的东西不起作用)。没有那么多循环和变量,有没有更简单的方法将字符串转换为复数?
一个 regular expression 可以解析每一行:
#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;
}
产生(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)