从字符串中解析复数,考虑语法变化
Parse complex number from string, considering syntax variations
我正在制作一个控制台应用程序,我可以在其中输入复数。一切正常,但我想在输入格式方面更加灵活。现在它只接受 a+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 == ' ')
return { a, 0 };
else if (ss >> b >> i && i == 'i')
return { 0, i };
在我的最后一行之前,它不起作用,因为>>通过 ss。字符串中不会有任何空格。我不确定如何在不重新转换 ss 的情况下更改它(我认为这不是最好的方法)
而且我不确定如何过滤掉任何被转换为整数并发送的随机字符,检查"\0"感觉错误。
谢谢!
(顺便说一句,返回 {true} 转到被检查的类的m_fail,这是我能想到的最简单的错误处理方法,但我是新手,所以如果您有任何关于该主题的文档,我很想阅读更多)
我已经建议编写一个小的解析器(例如,基于语法图,如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
科里鲁的现场演示
在摆弄时,我仍然意识到一些弱点,例如 由于 +
和 45
之间的空格,无法读取1.23 + 45i
。因此,使用更多的代码,这肯定可以改进。另一方面。。。OP没有具体说明应该在哪里接受空格,在哪里不接受。
恢复旧线程,但这里有一个更简洁的替代方案,它使用 std::complex 和 std::regex:
#include <stdexcept>
#include <complex>
#include <regex>
#include <string>
std::complex<double> ParseComplex(std::string const &complex_str)
{
std::regex complex_regex("^([+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?)[+-]([+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?)?(i)$");
std::regex real_imag_regex("^([+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?)(i)?$");
std::smatch complex_match;
std::smatch real_imag_match;
if (std::regex_search(std::cbegin(complex_str), std::cend(complex_str), complex_match, complex_regex)) {
return std::complex<double>(std::stod(complex_match[1].str()), complex_match[4].str().empty() ? 1.0 : std::stod(complex_match[4].str()));
}
else if (std::regex_search(std::cbegin(complex_str), std::cend(complex_str), real_imag_match, real_imag_regex)) {
if (!real_imag_match[3].str().empty()) {
return std::complex<double>(0.0, std::stod(real_imag_match[1].str()));
}
else {
return std::complex<double>(std::stod(real_imag_match[1].str()), 0.0);
}
}
throw std::invalid_argument("Does not contain a complex number");
}
相关文章:
- 1d 智能指针不适用于语法 (*)++
- 助记符和指向成员语法的指针
- 有人能分解一下这个c++模板的语法吗
- C++避免重复声明的语法是什么
- QMetaObject invokeMethod的基于函数指针的语法
- C++取消引用指针.为什么会发生变化
- 为什么在读取文件大小时文件IO速度会发生变化
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 为什么cudaMemGetInfo报告设备内存总量的变化
- 单独定义模板化嵌套类方法的正确语法
- 如何避免LED在循环状态变化中闪烁?
- 共享指针和具有自定义删除程序的唯一指针之间的语法差异背后的任何原因
- 当 I2C 值在C++中发生变化时收到通知
- 错误 C2760:语法错误:映射迭代器上意外的标记"标识符",预期的";"
- 为什么我会收到错误 C2143 语法错误:缺少"*"之前的';'?
- C 变化函数语法
- 从字符串中解析复数,考虑语法变化
- 在气的精神中回滚替代语法分析器的变化
- 理解构造函数定义块的语法变化