模拟扫描( "%1d" ) 用于C++ (std::cin)
Analog scanf("%1d") for C++ (std::cin)
我正在寻找一些模拟扫描("%1d",&序列)用于std::cin>>序列。
例如:
for ( ; scanf("%1d", &sequence) == 1; ) {
printf("%d ", sequence);
}
标准丁: 5341235
标准输出: 5 3 4 1 2 3 5
它在C++中是如何工作的?!
for ( ; std::cin >> *some_magic* sequence; ) {
std::cout << sequence << " ";
}
如果你愿意,你可以这样做(sequence
变量必须是char
类型)
for ( ; std::cin.read(&sequence,1); ) {
sequence-='0';
std::cout << sequence << " ";;
}
关于输入解析,不幸的是,IOStreams 中缺少许多功能,这些功能存在于scanf()
中。为数值类型设置字段宽度就是其中之一(另一个是匹配输入中的字符串)。假设你想保持格式化的输入,处理它的一种方法是创建一个过滤流缓冲区,该缓冲区在给定数量的字符后注入一个空格字符。
另一种方法是编写自定义std::num_get<char>
方面,将其imbue()
到当前流中,然后仅设置宽度。实际的字符解析将观察是否到达流的末尾或超过允许的字符数,而不是注入空格。使用此方面的相应代码将设置自定义std::locale
但看起来就像人们期望的那样:
int main() {
std::istringstream in("1234567890123456789");
std::locale loc(std::locale(), new width_num_get);
in.imbue(loc);
int w(0);
for (int value(0); in >> std::setw(++w) >> value; ) {
std::cout << "value=" << value << "n";
}
}
这是一个相应的std::num_get<char>
方面的有点幼稚的实现,它只是收集适当的数字(假设以 10 为基数),然后只是调用 std::stoi()
来转换值。它可以更灵活、更高效地完成,但你得到的图片是:
#include <iostream>
#include <streambuf>
#include <sstream>
#include <locale>
#include <string>
#include <iomanip>
#include <cctype>
struct width_num_get
: std::num_get<char> {
auto do_get(iter_type it, iter_type end, std::ios_base& fmt,
std::ios_base::iostate& err, long& value) const
-> iter_type override {
int width(fmt.width(0)), count(0);
if (width == 0) {
width = -1;
}
std::string digits;
if (it != end && (*it == '-' || *it == '+')) {
digits.push_back(*it++);
++count;
}
while (it != end && count != width && std::isdigit(static_cast<unsigned char>(*it))) {
digits.push_back(*it);
++it;
++count;
}
try { value = std::stol(digits); }
catch (...) { err |= std::ios_base::failbit; } // should probably distinguish overflow
return it;
}
};
第一种描述的方法可以使用这样的代码来读取宽度增加的整数(我使用不同的宽度来表明它可以灵活地设置):
int main() {
std::istringstream in("1234567890123456789");
int w(0);
for (int value(0); in >> fw(++w) >> value; ) {
std::cout << "value=" << value << "n";
}
}
当然,整个魔力在于自定义操纵器的小fw()
:如果当前使用的流缓冲区不是适当的类型,它会安装过滤流缓冲区,并设置字符的数量,之后应注入空格。过滤流缓冲区读取单个字符,并在相应数量的字符后注入一个空格。代码可能是这样的(流完成后,目前不会进行清理 - 我接下来会添加):
#include <iostream>
#include <streambuf>
#include <sstream>
class fieldbuf
: public std::streambuf {
std::streambuf* sbuf;
int width;
char buffer[1];
int underflow() {
if (this->width == 0) {
buffer[0] = ' ';
this->width = -1;
}
else {
int c = this->sbuf->snextc();
if (c == std::char_traits<char>::eof()) {
return c;
}
buffer[0] = std::char_traits<char>::to_char_type(c);
if (0 < this->width) {
--this->width;
}
}
this->setg(buffer, buffer, buffer + 1);
return std::char_traits<char>::to_int_type(buffer[0]);
}
public:
fieldbuf(std::streambuf* sbuf): sbuf(sbuf), width(-1) {}
void setwidth(int width) { this->width = width; }
};
struct fw {
int width;
fw(int width): width(width) {}
};
std::istream& operator>> (std::istream& in, fw const& width) {
fieldbuf* fbuf(dynamic_cast<fieldbuf*>(in.rdbuf()));
if (!fbuf) {
fbuf = new fieldbuf(in.rdbuf());
in.rdbuf(fbuf);
static int index = std::ios_base::xalloc();
in.pword(index) = fbuf;
in.register_callback([](std::ios_base::event ev, std::ios_base& stream, int index){
if (ev == std::ios_base::copyfmt_event) {
stream.pword(index) = 0;
}
else if (ev == std::ios_base::erase_event) {
delete static_cast<fieldbuf*>(stream.pword(index));
stream.pword(index) = 0;
}
}, index);
}
fbuf->setwidth(width.width);
return in;
}
相关文章:
- C++中的cin.ignore()函数不适用于整个流
- 在while循环中输入带有std::cin的字符串后,控制台会输出大量胡言乱语
- Problems with std::cin.fail()
- 检查不带转换的扫描格式
- 由cin中的字符串中未捕获空白引起的分割错误
- 在C++中使用Cin,我如何在1行中输入
- 将 cin 限制为只有一个
- cin >> int 给定一个字符串将 int 赋值为 0
- istream std::cin如何修改自定义istream缓冲区
- C++ 将 CIN 值存储到任何类型的数组中
- 为什么无论你输入什么,这"while(cin.get(str,3))"只运行一次?
- cin 的十进制输入验证?
- Turbo C++ cin() 不能与 gets() 一起使用
- 使用 cin 时接受小数点后的 2 位数字
- 在 std::getline 和 std::cin 期间卡在循环中
- 我无法在Visual Studio代码中使用CIN输入答案,它说输入您的年龄,但它说只读文本编辑器如何解决这个问题?
- 为什么我的两个 cin 语句没有在程序结束时运行?
- C++ cin.ignore() 跳过循环
- 模拟扫描( "%1d" ) 用于C++ (std::cin)
- 如何在c++中不使用cin扫描字符串