有没有办法在遇到 `\n` 时停止 std::cin
Is there a way to stop std::cin when it encounters a `\n`
除了一件事,我编写的代码运行良好。我编写此代码的任务是将数据作为空格分隔的双精度字符串输入到程序中。并且它们的精度可能大于 10^-25。所以我自己制作了 class 来处理这个问题。
问题是,当我编写代码时,每次按下 enter 时,我都通过在控制台中手动输入两个值来测试它,这样我的程序就可以理解一个 double 的结束位置和另一个开始的位置(它正在寻找基本上 '\n'
)。
现在我真的需要调整此代码以处理我的任务输入(空格分隔的双精度列表,如 2.521 32.12334656 23.21 .....
)。但是我在重载的 >> 运算符中遇到了 getline 问题。它只是吃掉 '\n'
字符并开始寻找更多输入。我能让它工作的唯一方法是手动输入值并在最后一个值之后手动输入一个额外的空格,然后才按回车键。
我正在寻求你的帮助。
完整代码如下:
#include <iostream>
#include <string>
#include <algorithm>
class BigNumber {
private:
std::string fullPart;
std::string floatPart;
public:
BigNumber() : fullPart("0"), floatPart("0") {}
friend std::ostream & operator << (std::ostream & os, const BigNumber & bn);
friend std::istream & operator >> (std::istream & os, BigNumber & bn);
void operator+=(BigNumber & bn);
};
int main()
{
BigNumber bn, bntemp;
while (std::cin >> bntemp)
{
bn += bntemp;
if (std::cin.peek() == '\n')
break;
}
std::cout << bn << std::endl;
return 0;
}
void addFullPart(const std::string & add, std::string & add_to)
{
auto addConv = std::stold(add);
auto addToConv = std::stold(add_to);
auto newFull = std::to_string(addConv + addToConv);
add_to = std::string(newFull.begin(), std::find(newFull.begin(), newFull.end(), '.'));
}
bool carryReminder(std::string & add_to, int32_t indx_from)
{
for (auto curr = indx_from; curr >= 0; --curr)
{
if (add_to[curr] != '9')
{
++(add_to[curr]);
return true;
}
else
add_to[curr] = '0';
}
return false;
}
std::pair<std::string, int32_t> addFloatPart(std::string & add, std::string & add_to)
{
std::string resultFloat;
int32_t reminderReturn{};
// don't forget to reverse str
if (add.size() != add_to.size())
{
// add remaining 0's
if (add.size() < add_to.size())
{
while (add.size() != add_to.size())
{
auto tempBigger = add_to.back();
add_to.pop_back();
resultFloat.push_back(tempBigger);
}
}
else
{
while (add.size() != add_to.size())
{
auto tempBigger = add.back();
add.pop_back();
resultFloat.push_back(tempBigger);
}
}
}
// now they are equal and have a form of 120(3921) 595
for (int32_t i = add_to.size() - 1; i >= 0; --i)
{
int32_t add_toDigit = add_to[i] - '0';
int32_t addDigit = add[i] - '0';
if (add_toDigit + addDigit >= 10)
{
resultFloat.append(std::to_string((add_toDigit + addDigit) - 10));
// we have a remainder
if (i == 0 || !carryReminder(add_to, i - 1))
reminderReturn = 1;
}
else
{
resultFloat.append(std::to_string(add_toDigit + addDigit));
}
}
std::reverse(resultFloat.begin(), resultFloat.end());
return std::make_pair(resultFloat, reminderReturn);
}
std::ostream & operator<<(std::ostream & os, const BigNumber & bn)
{
os << bn.fullPart << "." << bn.floatPart;
return os;
}
std::istream & operator>>(std::istream & is, BigNumber & bn)
{
std::string temp;
std::getline(is, temp, ' ');
auto fullPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.'));
auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end());
bn.floatPart = floatPartTemp;
bn.fullPart = fullPartTemp;
return is;
}
void BigNumber::operator+=(BigNumber & bn)
{
auto pair = addFloatPart(bn.floatPart, floatPart);
floatPart = pair.first;
if (pair.second > 0)
addFullPart(std::to_string(std::stoi(bn.fullPart) + 1), fullPart);
else
addFullPart(bn.fullPart, fullPart);
}
我建议你先用getline
读一行。然后你可以制作一个 istringstream
并在上面使用你的 >>
。具体来说,您可以添加 #include <sstream>
并将 main
函数更改为以下内容:
int main()
{
BigNumber bn, bntemp;
std::string temp;
std::getline(std::cin, temp);
std::istringstream ln(temp);
while (ln.good()) {
ln >> bntemp;
bn += bntemp;
}
std::cout << bn << std::endl;
return 0;
}
也许你可以使用
std::string temp;
is >> temp;
而不是 std::getline()
。
如果我没记错的话,会在空格处打断并将换行符保留在缓冲区中。
需要进行两处更改。在main
放弃了 peek 方法。太脆了。
int main()
{
BigNumber bn, bntemp;
std::string line;
std::getline(std::cin, line);
std::stringstream stream(line);
while (stream >> bntemp)
{
bn += bntemp;
}
std::cout << bn << std::endl;
return 0;
}
并且在operator>>
std::istream & operator >> (std::istream & is, BigNumber & bn)
{
std::string temp;
// also do NOTHING if the read fails!
if (std::getline(is, temp, ' '))
{
// recommend some isdigit testing in here to make sure you're not
// being fed garbage. Set fail flag in stream and bail out.
auto floatPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.'));
// if there is no . you are in for a world of hurt here
auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end());
bn.floatPart = ;
bn.fullPart = fullPartTemp;
}
return is;
}
所以它看起来应该更像
std::istream & operator >> (std::istream & is, BigNumber & bn)
{
std::string temp;
if (std::getline(is, temp, ' '))
{
if (std::all_of(temp.cbegin(), temp.cend(), [](char ch) { return isdigit(ch) || ch == '.'; }))
{
auto dotpos = std::find(temp.begin(), temp.end(), '.');
bn.fullPart = std::string(temp.begin(), dotpos);
std::string floatPartTemp;
if (dotpos != temp.end())
{
floatPartTemp = std::string(dotpos + 1, temp.end());
}
bn.floatPart = floatPartTemp;
}
else
{
is.setstate(std::ios::failbit);
}
}
return is;
}
除了一件事,我编写的代码运行良好。我编写此代码的任务是将数据作为空格分隔的双精度字符串输入到程序中。并且它们的精度可能大于 10^-25。所以我自己制作了 class 来处理这个问题。
问题是,当我编写代码时,每次按下 enter 时,我都通过在控制台中手动输入两个值来测试它,这样我的程序就可以理解一个 double 的结束位置和另一个开始的位置(它正在寻找基本上 '\n'
)。
现在我真的需要调整此代码以处理我的任务输入(空格分隔的双精度列表,如 2.521 32.12334656 23.21 .....
)。但是我在重载的 >> 运算符中遇到了 getline 问题。它只是吃掉 '\n'
字符并开始寻找更多输入。我能让它工作的唯一方法是手动输入值并在最后一个值之后手动输入一个额外的空格,然后才按回车键。
我正在寻求你的帮助。
完整代码如下:
#include <iostream>
#include <string>
#include <algorithm>
class BigNumber {
private:
std::string fullPart;
std::string floatPart;
public:
BigNumber() : fullPart("0"), floatPart("0") {}
friend std::ostream & operator << (std::ostream & os, const BigNumber & bn);
friend std::istream & operator >> (std::istream & os, BigNumber & bn);
void operator+=(BigNumber & bn);
};
int main()
{
BigNumber bn, bntemp;
while (std::cin >> bntemp)
{
bn += bntemp;
if (std::cin.peek() == '\n')
break;
}
std::cout << bn << std::endl;
return 0;
}
void addFullPart(const std::string & add, std::string & add_to)
{
auto addConv = std::stold(add);
auto addToConv = std::stold(add_to);
auto newFull = std::to_string(addConv + addToConv);
add_to = std::string(newFull.begin(), std::find(newFull.begin(), newFull.end(), '.'));
}
bool carryReminder(std::string & add_to, int32_t indx_from)
{
for (auto curr = indx_from; curr >= 0; --curr)
{
if (add_to[curr] != '9')
{
++(add_to[curr]);
return true;
}
else
add_to[curr] = '0';
}
return false;
}
std::pair<std::string, int32_t> addFloatPart(std::string & add, std::string & add_to)
{
std::string resultFloat;
int32_t reminderReturn{};
// don't forget to reverse str
if (add.size() != add_to.size())
{
// add remaining 0's
if (add.size() < add_to.size())
{
while (add.size() != add_to.size())
{
auto tempBigger = add_to.back();
add_to.pop_back();
resultFloat.push_back(tempBigger);
}
}
else
{
while (add.size() != add_to.size())
{
auto tempBigger = add.back();
add.pop_back();
resultFloat.push_back(tempBigger);
}
}
}
// now they are equal and have a form of 120(3921) 595
for (int32_t i = add_to.size() - 1; i >= 0; --i)
{
int32_t add_toDigit = add_to[i] - '0';
int32_t addDigit = add[i] - '0';
if (add_toDigit + addDigit >= 10)
{
resultFloat.append(std::to_string((add_toDigit + addDigit) - 10));
// we have a remainder
if (i == 0 || !carryReminder(add_to, i - 1))
reminderReturn = 1;
}
else
{
resultFloat.append(std::to_string(add_toDigit + addDigit));
}
}
std::reverse(resultFloat.begin(), resultFloat.end());
return std::make_pair(resultFloat, reminderReturn);
}
std::ostream & operator<<(std::ostream & os, const BigNumber & bn)
{
os << bn.fullPart << "." << bn.floatPart;
return os;
}
std::istream & operator>>(std::istream & is, BigNumber & bn)
{
std::string temp;
std::getline(is, temp, ' ');
auto fullPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.'));
auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end());
bn.floatPart = floatPartTemp;
bn.fullPart = fullPartTemp;
return is;
}
void BigNumber::operator+=(BigNumber & bn)
{
auto pair = addFloatPart(bn.floatPart, floatPart);
floatPart = pair.first;
if (pair.second > 0)
addFullPart(std::to_string(std::stoi(bn.fullPart) + 1), fullPart);
else
addFullPart(bn.fullPart, fullPart);
}
我建议你先用getline
读一行。然后你可以制作一个 istringstream
并在上面使用你的 >>
。具体来说,您可以添加 #include <sstream>
并将 main
函数更改为以下内容:
int main()
{
BigNumber bn, bntemp;
std::string temp;
std::getline(std::cin, temp);
std::istringstream ln(temp);
while (ln.good()) {
ln >> bntemp;
bn += bntemp;
}
std::cout << bn << std::endl;
return 0;
}
也许你可以使用
std::string temp;
is >> temp;
而不是 std::getline()
。
如果我没记错的话,会在空格处打断并将换行符保留在缓冲区中。
需要进行两处更改。在main
放弃了 peek 方法。太脆了。
int main()
{
BigNumber bn, bntemp;
std::string line;
std::getline(std::cin, line);
std::stringstream stream(line);
while (stream >> bntemp)
{
bn += bntemp;
}
std::cout << bn << std::endl;
return 0;
}
并且在operator>>
std::istream & operator >> (std::istream & is, BigNumber & bn)
{
std::string temp;
// also do NOTHING if the read fails!
if (std::getline(is, temp, ' '))
{
// recommend some isdigit testing in here to make sure you're not
// being fed garbage. Set fail flag in stream and bail out.
auto floatPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.'));
// if there is no . you are in for a world of hurt here
auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end());
bn.floatPart = ;
bn.fullPart = fullPartTemp;
}
return is;
}
所以它看起来应该更像
std::istream & operator >> (std::istream & is, BigNumber & bn)
{
std::string temp;
if (std::getline(is, temp, ' '))
{
if (std::all_of(temp.cbegin(), temp.cend(), [](char ch) { return isdigit(ch) || ch == '.'; }))
{
auto dotpos = std::find(temp.begin(), temp.end(), '.');
bn.fullPart = std::string(temp.begin(), dotpos);
std::string floatPartTemp;
if (dotpos != temp.end())
{
floatPartTemp = std::string(dotpos + 1, temp.end());
}
bn.floatPart = floatPartTemp;
}
else
{
is.setstate(std::ios::failbit);
}
}
return is;
}