Analog scanf ("% 1d") for C ++ (std :: cin)

I am looking for several analog scanf ("% 1d" and sequence) for the sequence std :: cin β†’.

For instance:

for ( ; scanf("%1d", &sequence) == 1; ) { printf("%d ", sequence); } 
  stdin: 5341235 
  stdout: 5 3 4 1 2 3 5 

How does it work in C ++ ?!

 for ( ; std::cin >> *some_magic* sequence; ) { std::cout << sequence << " "; } 
+6
source share
2 answers

you can do this if you want (the sequence variable must be of type char )

 for ( ; std::cin.read(&sequence,1); ) { sequence-='0'; std::cout << sequence << " ";; } 
+3
source

Regarding input parsing, unfortunately, IOStreams, which is present for scanf() , lacks a number of functions. Setting the field width for numeric types is one of them (the other corresponds to the lines in the inputs). Assuming you want to stay with formatted input, one way to deal with it is to create a filter stream buffer that enters a space character after a given number of characters.

Another approach is to write a custom facet std::num_get<char> , in imbue() in the current thread, and then just set the width. Instead of entering spaces, the actual parsing will be observed if the end of the stream is reached or the number of characters is exceeded. The appropriate code to use this face should set up custom std::locale , but otherwise look like you would expect:

 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"; } } 

Here is a somewhat naive implementation of the corresponding facet std::num_get<char> , which simply collects the corresponding numbers (assuming base 10) and then simply calls std::stoi() to convert the value. It can be made more flexible and more efficient, but you will get an image:

 #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; } }; 

In the first approach described, you can use this code to read integers with increasing width (I use different widths to show that it can be flexibly set):

 int main() { std::istringstream in("1234567890123456789"); int w(0); for (int value(0); in >> fw(++w) >> value; ) { std::cout << "value=" << value << "\n"; } } 

Of course, all the magic is in little fw() , which is a customizable manipulator: it sets the filtering stream buffer if the current used stream buffer does not match the corresponding type and sets the number for characters, after which you need to enter the space. The filter stream buffer reads individual characters and simply enters a space after the appropriate number of characters. The code may be something like this (which currently does not clean up after the stream finishes - I will add the following):

 #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; } 
+2
source

Source: https://habr.com/ru/post/980493/


All Articles