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

I'm looking for some analog scanf("%1d", &sequence) for std::cin >> sequence.
For example:
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 << " ";
}

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

With respect to input parsing there are a number of features unfortunately missing from IOStreams which are present for scanf(). Setting a field width for numeric types is one of them (another one is matching strings in inputs). Assuming you want to stay with formatted input, one way to deal with it is to create a filtering stream buffer which injects a space character after a given number of characters.
Another approach consists of writing a custom std::num_get<char> facet, to imbue() it into the current stream, and then just set up width. Instead of injecting spaces the actual character parsing would observe if either the end of the stream is reached or the number of allowed characters is exceeded. The corresponding code to use this facet would set up a custom std::locale but otherwise look like one 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 a corresponding std::num_get<char> facet which just collects the appropriate digits (assuming base 10) and then just calls std::stoi() to get the value converted. It can be done more flexible and more efficient but you get the picture:
#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;
}
};
The first described approach could use code like this for reading integers with increasing width (I'm using different width to show that it can flexibly be 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, the entire magic is in the little fw() which is a custom manipulator: it installs a filtering stream buffer if the currently used stream buffer isn't of the appropriate type and set the number for characters after which the a space should be injected. The filtering stream buffer reads individual characters and simply injects a space after the corresponding number of characters. The code could be something like this (which currently doesn't do clean-up once the stream is done - I'll add that next):
#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;
}

Related

How to read string from stdin until meet blank lines

Consider a simple program. It must take string from stdin and save to variable.
It is not stated how many lines of input will be taken, but program must terminate if meet newline.
For example:
stdin:
abc
abs
aksn
sjja
\n
I tried but it doesn't work. Here is my code:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
// Constant
#define max 100000
struct chuoi
{
char word[10];
};
chuoi a[max];
void readStr()
{
int i=0;
while ( fgets(a[i].word, 10,stdin) != NULL)
{
if (a[i].word[0] == ' ') break;
a[i].word[strlen(a[i].word)-1] = '\0'; //replaced \n by \0
i++;
}
//length = i;
}
int main()
{
readStr();
return 0;
}
So, how to solve this problem?
One alternative here is to use std::getline to get each line. If the line is empty, or the input fails, then exit the loop.
void readStr()
{
std::string str;
while ( std::getline(std::cin, str) && str.length() )
{
// use the string...
}
}
Adding the std::getline and use of std::vector to your sample code, and keeping with the spirit of your original sample;
#include <string>
#include <iostream>
#include <vector>
const std::size_t Max = 100000;
struct chuoi
{
explicit chuoi(std::string const& str) : word(str)
{
}
std::string word;
};
void readStr(std::vector<chuoi>& a)
{
std::string str;
while ( std::getline(std::cin, str) && str.length() )
{
a.push_back(chuoi(str));
}
}
void writeStr(std::vector<chuoi> const& a)
{
for (auto i = a.begin(); i != a.end(); ++i) {
std::cout << i->word << std::endl;
}
}
int main()
{
std::vector<chuoi> a;
a.reserve(Max);
readStr(a);
writeStr(a);
return 0;
}
To solve you immediate problem, minimal changes in the code can be made as follows;
void readStr()
{
int i = 0;
while ( fgets(a[i].word, 10, stdin) != NULL)
{
a[i].word[strlen(a[i].word) - 1] = '\0'; // transform the end of line character to NULL
if (strlen(a[i].word) == 0) {
break;
}
i++;
}
}
If the standard input will always be used (stdin), the gets function can also be used;
while ( gets(a[i].word) != NULL)
{
if (strlen(a[i].word) == 0) {
break;
}
i++;
}
Notes;
fgets reads until the "enter" key on the stdin but includes the new line character
gets also reads until the return, but excludes the new line character
Both functions NULL terminate the input
Be careful of the form of gets it does not check for buffer overflow conditions
I would do something like this:
#include <string>
#include <iostream>
int main()
{
std::string line; // will contain each line of input
// Stop when line is empty or when terminal input has an error
while(std::getline(std::cin, line) && !line.empty())
{
// do stuff with line
}
}

C++ detecting if input is Int or String

I'm a C++ newbie who came from Java, so I need some guidance on some really basic issues I'm stumbling upon as I go.
I'm reading lines from a file, and each line consists of 6 strings/ints, which will be sent as parameters to a temporary variable.
Example:
Local1,Local2,ABC,200,300,asphalt
However, there are two subtypes of variable. One has a string as the last parameter (like 'asphalt' in the example above). The other one has an int instead. I have a method that reads each parameter and sends it to a variable, but how do I detect if the last bit of string is an integer or a string beforehand, so I know if I should send it to a Type1 variable or a Type2 one?
Many thanks!
Since you want to determine the type of the last column, then this ought to work:
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <sstream>
#include <cctype>
#include <algorithm>
enum Types {
NONE,
STRING,
INTEGER,
DOUBLE
};
struct Found {
std::string string_val;
int integer_val;
double double_val;
enum Types type;
};
//copied verbatim from:
//http://stackoverflow.com/a/2845275/866930
inline bool isInteger(const std::string &s) {
if(s.empty() || ((!std::isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
char * p ;
std::strtol(s.c_str(), &p, 10);
return (*p == 0);
}
//modified slightly for decimals:
inline bool isDouble(const std::string &s) {
if(s.empty() || ((!std::isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false ;
char * p ;
std::strtod(s.c_str(), &p) ;
return (*p == 0);
}
bool isNotAlpha(char c) {
return !(std::isalpha(c));
}
//note: this searches for strings containing only characters from the alphabet
//however, you can modify that behavior yourself.
bool isString (const std::string &s) {
std::string::const_iterator it = std::find_if(s.begin(), s.end(), isNotAlpha);
return (it == s.end()) ? true : false;
}
void determine_last_column (const std::string& str, Found& found) {
//reset found:
found.integer_val = 0;
found.double_val = 0;
found.string_val = "";
found.type = NONE;
std::string temp;
std::istringstream iss(str);
int column = 0;
char *p;
while(std::getline(iss, temp, ',')) {
if (column == 5) {
//now check to see if the column is an integer or not:
if (isInteger(temp)) {
found.integer_val = static_cast<int>(std::strtol(temp.c_str(), &p, 10));
found.type = INTEGER;
}
else if (isDouble(temp)) {
found.double_val = static_cast<double>(std::strtod(temp.c_str(), &p));
found.type = DOUBLE;
}
else if (isString(temp)) {
found.string_val = temp;
found.type = STRING;
}
}
++column;
}
if (found.type == INTEGER) {
std::cout << "An integer was found: " << found.integer_val << std::endl;
}
else if(found.type == DOUBLE) {
std::cout << "A double was found: " << found.double_val << std::endl;
}
else if(found.type == STRING) {
std::cout << "A string was found: " << found.string_val << std::endl;
}
else {
std::cout << "A valid type was not found! Something went wrong..." << std::endl;
}
}
int main() {
std::string line_t1 = "Local1,Local2,ABC,200,300,asphalt";
std::string line_t2 = "Local1,Local2,ABC,200,300,-7000.3";
Found found;
determine_last_column(line_t1, found);
determine_last_column(line_t2, found);
return 0;
}
This outputs and correctly assigns the appropriate value:
A string was found: asphalt
An integer was found: -7000.3
This version works on int, double, string; does not require boost; and, is plain vanilla C++98.
REFERENCES:
UPDATE:
This version now supports both positive and negative numbers that are integers or doubles, in addition to strings.
First, create an array that can store both strings and integers:
std::vector<boost::variant<std::string, int>> items;
Second, split the input string on commas:
std::vector<std::string> strings;
boost::split(strings, input, boost::is_any_of(","));
Last, parse each token and insert it into the array:
for (auto&& string : strings) {
try {
items.push_back(boost::lexical_cast<int>(string));
} catch(boost::bad_lexical_cast const&) {
items.push_back(std::move(string));
}
}

C++ Hex string to byte array

First off, I've Googled this question over the past few days but everything I find doesn't work. I don't receive runtime errors but when I type in the same key (in the form of a hex string) that the program generates to encrypt, decryption fails (but using the generated key throughout the program works fine). I'm trying to enter a hex string (format: 00:00:00...) and turn it into a 32-byte byte array. The input comes from getpass(). I've done this before in Java and C# but I'm new to C++ and everything seems much more complicated. Any help would be greatly appreciated :) Also I'm programming this on a linux platform so I'd like to avoid Windows-only functions.
Here is an example of what I've tried:
char *pass = getpass("Key: ");
std::stringstream converter;
std::istringstream ss( pass );
std::vector<byte> bytes;
std::string word;
while( ss >> word )
{
byte temp;
converter << std::hex << word;
converter >> temp;
bytes.push_back( temp );
}
byte* keyBytes = &bytes[0];
If your input has format: AA:BB:CC,
you could write something like this:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdint>
struct hex_to_byte
{
static uint8_t low(const char& value)
{
if(value <= '9' && '0' <= value)
{
return static_cast<uint8_t>(value - '0');
}
else // ('A' <= value && value <= 'F')
{
return static_cast<uint8_t>(10 + (value - 'A'));
}
}
static uint8_t high(const char& value)
{
return (low(value) << 4);
}
};
template <typename InputIterator>
std::string from_hex(InputIterator first, InputIterator last)
{
std::ostringstream oss;
while(first != last)
{
char highValue = *first++;
if(highValue == ':')
continue;
char lowValue = *first++;
char ch = (hex_to_byte::high(highValue) | hex_to_byte::low(lowValue));
oss << ch;
}
return oss.str();
}
int main()
{
std::string pass = "AB:DC:EF";
std::string bin_str = from_hex(std::begin(pass), std::end(pass));
std::vector<std::uint8_t> v(std::begin(bin_str), std::end(bin_str)); // bytes: [171, 220, 239]
return 0;
}
How about this?
Read it as a word and operate on it after?
You can do any size checking format checking in convert().
#include <iostream>
#include <string>
#include <vector>
char convert(char c)
{
using namespace std;
// do whatever decryption stuff you want here
return c;
}
void test()
{
using namespace std;
string word;
cin >> word;
vector<char> password;
for (int i = 0; i < word.length(); i++)
{
password.push_back(convert(word[i]));
}
for (int i = 0; i < password.size(); i++)
{
cout << password[i];
}
cout << "";
}
int main()
{
using namespace std;
char wait = ' ';
test();
cin >> wait;
}
Are there specific reasons for not using cin here?

Using C++ splitting a section string which is in "[General Setting]" format

I am new to C++, i want to read ini file which has section and key - value pair.
Depending on the section, i want to read the value for corresponding key.
Primarily, i want to read the section which is enclosed in square brackets.
Please help.
Thank you.
For real INI file parsing, I highly suggest the iniparser library. It is excellently documented and easy to use in both C and C++ programs.
If you are only interested in parsing strings of the form [Section name], you could do the following: Find first '[' and last ']' for the string and mark the positions. If both characters have been found, take the section name to be substring between the positions you identified.
Assuming you are using an std::string, you can do the following:
std::string myString = " [Section name] ";
std::size_t start = myString.find_first_of( '[' );
std::size_t end = myString.find_last_of( ']' );
std::string sectionName;
if( start != std::string::npos && end != std::string::npos )
{
sectionName = myString.substr(start + 1, end - 1);
}
std::cout << sectionName << std::endl;
This snippet should show you the basic logic for parsing an ini file and skipping # or ; prefixed lines which are treated as comments
this needs sanity checks for group names, names and values, but should suffice as a demonstration:
#include <iostream>
#include <string>
#include <map>
//
// a simple ini file parser (doesn't check for validity of name field length wise or if it has = char
// to demonstrate basic parsing
//
class IniFile
{
public:
enum { MAX_LINE_LEN = 10*1024 };
class MalformedInputException : public std::exception
{
public:
const char* what() const throw() { return "Input is not a valid or well formed ini file"; }
};
typedef std::map<std::string, std::string> Properties;
IniFile(){}
virtual ~IniFile(){}
std::istream& load(std::istream& in)
{
char lineBuffer[MAX_LINE_LEN];
std::string curGroup = "";
while(!in.eof())
{
in.getline(lineBuffer, MAX_LINE_LEN);
//std::cout<<"line buffer : {"<<lineBuffer<<"}"<<std::endl;
std::string line = trim(lineBuffer);
//std::cout<<"trimmed : {"<<line<<"}"<<std::endl;
// we process only non-empty / non-comment lines
if(line.size() > 0 && line[0] != '#' && line[0] != ';')
{
if(line[0] == '[' && line[line.size() - 1] == ']')
{
curGroup = trim(line.substr(1, line.size() - 2));
}
else if(curGroup.size() > 0)
{
size_t index = line.find_first_of('=');
//todo: needs checks for valid name=value format here
Properties& props = m_props[curGroup]; // this will create new Properties if none exists
props[line.substr(0,index)] = line.substr(index+1);
}
else
{
throw MalformedInputException();
}
}
}
return in;
}
std::ostream& save(std::ostream& os) const
{
std::map<std::string, Properties>::const_iterator iter = m_props.begin();
while(iter != m_props.end())
{
os<<"["<<iter->first<<"]"<<std::endl;
Properties::const_iterator propIter = iter->second.begin();
while(propIter != iter->second.end())
{
os<<propIter->first<<"="<<propIter->second<<std::endl;
propIter++;
}
iter++;
}
return os;
}
std::string trim(const std::string& input)
{
static std::string WHITESPACES = "\r\n \t\b\a";
if(input.size() == 0){ return input; }
else
{
size_t start = 0;
for(size_t index = 0; index < input.size(); index++)
{
if(WHITESPACES.find(input[index]) < WHITESPACES.size())
{
start = index;
}
else
{
break;
}
}
size_t endIndex = input.size() - 1;
if(start == endIndex){ return ""; }
for(; endIndex > start; endIndex--)
{
char c = input.at(endIndex);
if(WHITESPACES.find_first_of(c) >= WHITESPACES.size())
{
break;
}
}
size_t length = endIndex - start + 1;
return input.substr(start, length);
}
}
private:
std::map<std::string, Properties> m_props;
};
inline std::ostream& operator << (std::ostream& os, const IniFile& iniFile)
{
return iniFile.save(os);
}
inline std::istream& operator >> (std::istream& in, IniFile& iniFile)
{
return iniFile.load(in);
}
#include <sstream>
int main(int argc, char** argv)
{
std::ostringstream ss;
ss<<"# sample ini file"<<std::endl;
ss<<"[Group1]"<<std::endl;
ss<<"foo=bar \n"<<std::endl;
ss<<"baz=foz"<<std::endl;
ss<<"; this is another comment"<<std::endl;
ss<<"[Group2]"<<std::endl;
ss<<"blanga=kukoo"<<std::endl;
std::string buf = ss.str();
std::istringstream sin(buf);
IniFile iniFile;
iniFile.load(sin);
iniFile.save(std::cout<<"Ini File Loaded : "<<std::endl);
return 0;
}

How to get the line number from a file in C++?

What would be the best way to get the line number of the current line in a file that I have opened with a ifstream? So I am reading in the data and I need to store the line number that it is on so that I can display it later if the data doesn't match the specifications.
If you don't want to limit yourself to std::getline, then you could use class derived from std::streambuf, and which keeps track of the current line number:
class CountingStreamBuffer : public std::streambuf { /* see below */ };
// open file
std::ifstream file("somefile.txt");
// "pipe" through counting stream buffer
CountingStreamBuffer cntstreambuf(file.rdbuf());
std::istream is(&cntstreambuf);
// sample usage
is >> x >> y >> z;
cout << "At line " << cntstreambuf.lineNumber();
std::getline(is, str);
cout << "At line " << cntstreambuf.lineNumber();
Here is a sample implementation of CountingStreamBuffer:
#include <streambuf>
class CountingStreamBuffer : public std::streambuf
{
public:
// constructor
CountingStreamBuffer(std::streambuf* sbuf) :
streamBuf_(sbuf),
lineNumber_(1),
lastLineNumber_(1),
column_(0),
prevColumn_(static_cast<unsigned int>(-1)),
filePos_(0)
{
}
// Get current line number
unsigned int lineNumber() const { return lineNumber_; }
// Get line number of previously read character
unsigned int prevLineNumber() const { return lastLineNumber_; }
// Get current column
unsigned int column() const { return column_; }
// Get file position
std::streamsize filepos() const { return filePos_; }
protected:
CountingStreamBuffer(const CountingStreamBuffer&);
CountingStreamBuffer& operator=(const CountingStreamBuffer&);
// extract next character from stream w/o advancing read pos
std::streambuf::int_type underflow()
{
return streamBuf_->sgetc();
}
// extract next character from stream
std::streambuf::int_type uflow()
{
int_type rc = streamBuf_->sbumpc();
lastLineNumber_ = lineNumber_;
if (traits_type::eq_int_type(rc, traits_type::to_int_type('\n')))
{
++lineNumber_;
prevColumn_ = column_ + 1;
column_ = static_cast<unsigned int>(-1);
}
++column_;
++filePos_;
return rc;
}
// put back last character
std::streambuf::int_type pbackfail(std::streambuf::int_type c)
{
if (traits_type::eq_int_type(c, traits_type::to_int_type('\n')))
{
--lineNumber_;
lastLineNumber_ = lineNumber_;
column_ = prevColumn_;
prevColumn_ = 0;
}
--column_;
--filePos_;
if (c != traits_type::eof())
return streamBuf_->sputbackc(traits_type::to_char_type(c));
else
return streamBuf_->sungetc();
}
// change position by offset, according to way and mode
virtual std::ios::pos_type seekoff(std::ios::off_type pos,
std::ios_base::seekdir dir,
std::ios_base::openmode mode)
{
if (dir == std::ios_base::beg
&& pos == static_cast<std::ios::off_type>(0))
{
lastLineNumber_ = 1;
lineNumber_ = 1;
column_ = 0;
prevColumn_ = static_cast<unsigned int>(-1);
filePos_ = 0;
return streamBuf_->pubseekoff(pos, dir, mode);
}
else
return std::streambuf::seekoff(pos, dir, mode);
}
// change to specified position, according to mode
virtual std::ios::pos_type seekpos(std::ios::pos_type pos,
std::ios_base::openmode mode)
{
if (pos == static_cast<std::ios::pos_type>(0))
{
lastLineNumber_ = 1;
lineNumber_ = 1;
column_ = 0;
prevColumn_ = static_cast<unsigned int>(-1);
filePos_ = 0;
return streamBuf_->pubseekpos(pos, mode);
}
else
return std::streambuf::seekpos(pos, mode);
}
private:
std::streambuf* streamBuf_; // hosted streambuffer
unsigned int lineNumber_; // current line number
unsigned int lastLineNumber_;// line number of last read character
unsigned int column_; // current column
unsigned int prevColumn_; // previous column
std::streamsize filePos_; // file position
};
From an ifstream point of view there is no line number. If you read in the file line by line, then you just have to keep track of it yourself.
Use std::getline to read each line in one by one. Keep an integer indicating the number of lines you have read: initialize it to zero and each time you call std::getline and it succeeds, increment it.
An inefficient but dead simple way is to have a function that given a stream, it counts the new line characters from the beginning of the stream to the current position.
int getCurrentLine(std::istream& is)
{
int lineCount = 1;
is.clear(); // need to clear error bits otherwise tellg returns -1.
auto originalPos = is.tellg();
if (originalPos < 0)
return -1;
is.seekg(0);
char c;
while ((is.tellg() < originalPos) && is.get(c))
{
if (c == '\n') ++lineCount;
}
return lineCount;
}
In some code I am working on, I am only interested to know the line number if invalid input is encountered, in which case import is aborted immediately. Since the function is called only once the inefficiency is not really a problem.
The following is a full example:
#include <iostream>
#include <sstream>
int getCurrentLine(std::istream& is)
{
int lineCount = 1;
is.clear(); // need to clear error bits otherwise tellg returns -1.
auto originalPos = is.tellg();
if (originalPos < 0)
return -1;
is.seekg(0);
char c;
while ((is.tellg() < originalPos) && is.get(c))
{
if (c == '\n') ++lineCount;
}
return lineCount;
}
void ReadDataFromStream(std::istream& s)
{
double x, y, z;
while (!s.fail() && !s.eof())
{
s >> x >> y >> z;
if (!s.fail())
std::cout << x << "," << y << "," << z << "\n";
}
if (s.fail())
std::cout << "Error at line: " << getCurrentLine(s) << "\n";
else
std::cout << "Read until line: " << getCurrentLine(s) << "\n";
}
int main(int argc, char* argv[])
{
std::stringstream s;
s << "0.0 0.0 0.0\n";
s << "1.0 ??? 0.0\n";
s << "0.0 1.0 0.0\n";
ReadDataFromStream(s);
std::stringstream s2;
s2 << "0.0 0.0 0.0\n";
s2 << "1.0 0.0 0.0\n";
s2 << "0.0 1.0 0.0";
ReadDataFromStream(s2);
return 0;
}