I am trying to read each 'char' of the input file and write in the output file until finds the '?' as the end of file . Every char is written in output file except the spaces between words. I dont know what's wrong in this code??
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream infile("in.txt");
ofstream outfile("out.txt");
char ch;
infile >> ch;
while(ch != '?')
{
outfile<<ch;
infile >> ch;
}
}
Try using noskipws on read...
infile >> noskipws >> ch;
The noskipws tells the input stream to not skip whitespace which it does by default.
istream operator >> ignores whitespace. Try this:
std::string s;
std::getline(infile,s,'?');
outfile << s;
The >> operator for input streams is generally associated with interpretation. For example, when reading strings it skips spaces. This may be the case when reading chars.
You ought to use the read method, for example:
infile.read(&ch, 1)
See http://www.cplusplus.com/reference/iostream/ifstream/ for reference
edit I forgot about the get method. That'll get you a single character, cast as an int. The read method is more geared for reading a chunk of data in one call.
#Andrew White has already pointed out how to fix the problem you've seen. I'll toss in my idea (typically for me, probably over-engineered) idea of how to do the rest of the job:
#pragma once
#if !defined(SENTINEL_ITERATOR_H_)
#define SENTINEL_ITERATOR_H_
#include <istream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT>,
class distance = ptrdiff_t>
class sentinel_iterator :
public std::iterator<std::input_iterator_tag,distance,void,void,void>
{
std::basic_istream<charT,traits> *is;
T value;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_istream<charT,traits> istream_type;
sentinel_iterator(istream_type& s)
: is(&s)
{ s >> value; }
sentinel_iterator(T const &s) : is(0), value(s) { }
const T &operator*() const { return value; }
const T *operator->() const { return &value; }
sentinel_iterator &operator++() {
(*is)>>value;
return *this;
}
sentinel_iterator &operator++(int) {
sentinel_iterator tmp = *this;
(*is)>>value;
return (tmp);
}
bool operator==(sentinel_iterator<T,charT,traits,distance> const &x) {
return value == x.value;
}
bool operator!=(sentinel_iterator<T,charT,traits,distance> const &x) {
return !(value == x.value);
}
};
#endif
Then the code becomes something like this:
#include <algorithm>
#include <fstream>
#include "sentinel_iterator.h"
int main() {
ifstream infile("in.txt");
ofstream outfile("out.txt");
infile >> noskipws;
std::copy(sentinel_iterator<char>(infile),
sentinel_iterator<char>('?'),
std::ostream_iterator<char>(outfile));
return 0;
}
Related
I'm reading a file word by word, but sometimes the long dash (or em dash) is in the middle of two words and I wanted to add that as another delimiter (besides the standard whitespace).
ifstream file;
file.open("example.txt");
string word;
while (file >> word)
{
cout << word << endl;
}
For example, the phrase "He was young—perhaps from twenty-eight to thirty—tall, slender" prints the words:
He
was
young—perhaps
from
twenty-eight
to
thirty—tall
slender
"twenty-eight" is fine, but "young" and "perhaps" (and "thirty" and "tall") are two different words and I wanted to read them as such.
How do I add the custom delimiter "—"?
Yes:
If you were wanting to treat a single character (like the normal dash '-') as a space I would use ctype facet. This type specifies how a local treats characters. In this case we can tell the facet that a '-' is a type of space.
#include <locale>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
// This is my facet:
// It adds the '-' character to the set of characters treated like a space.
class DashSepFacet: public std::ctype<char>
{
public:
typedef std::ctype<char> base;
typedef base::char_type char_type;
DashSepFacet(std::locale const& l) : base(table)
{
// Get the ctype facet of the current locale
std::ctype<char> const& defaultCType = std::use_facet<std::ctype<char> >(l);
// Copy the default flags for each character from the current facet
static char data[256];
for(int loop = 0; loop < 256; ++loop) {data[loop] = loop;}
defaultCType.is(data, data+256, table);
// Add the '-' as a space
table['-'] |= base::space;
}
private:
base::mask table[256];
};
int main()
{
// Create a stream (Create the locale) then imbue the stream.
std::fstream data;
data.imbue(std::locale(data.getloc(), new DashSepFacet(data.getloc())));
data.open("X3");
// Now you can use the stream like normal; your locale defines what
// is whitespace, so the operator `>>` will split on dash.
std::string word;
while(data >> word)
{
std::cout << "Word(" << word << ")\n";
}
}
Now we get:
> ./a.out
Word(He)
Word(was)
Word(young—perhaps)
Word(from)
Word(twenty)
Word(eight)
Word(to)
Word(thirty—tall)
Word(slender)
Unfortunately the em-dash is a unicode code point that is actually represented by 3 characters so the above technique does not work. Instead you can use the char_traits facet that tells the local to convert character sequences (usually used to convert between formats). In this case we write a version that converts the em-dash into a literal space character.
#include <locale>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <locale>
#include <string>
#include <iostream>
#include <fstream>
#include <cctype>
class PunctRemove: public std::codecvt<char,char,std::char_traits<char>::state_type>
{
bool do_always_noconv() const throw() { return false;}
int do_encoding() const throw() { return true; }
typedef std::codecvt<char,char,std::char_traits<char>::state_type> MyType;
typedef MyType::state_type state_type;
typedef MyType::result result;
virtual result do_in(state_type& s,
const char* from,const char* from_end,const char*& from_next,
char* to, char* to_limit, char*& to_next ) const
{
// Unicode for em-dash is
// e2 80 94
static int emdashpos = 0;
/*
* This function is used to filter the input
*/
for(from_next = from, to_next = to;from_next != from_end;++from_next)
{
// Note we do it this way.
// because the multi byte em-dash may be split across buffer boundaries.
if (emdashpos == 0 && *from_next == '\xe2') {
++emdashpos;
continue;
}
else if (emdashpos == 1 && *from_next == '\x80') {
++emdashpos;
continue;
}
else if (emdashpos == 2 && *from_next == '\x94') {
*to_next = ' ';
++to_next;
emdashpos=0;
continue;
}
// --- Account for times when we received some characters but not all
if (emdashpos != 0) {
from_next -= emdashpos;
emdashpos = 0;
}
// Normal processing.
*to_next = *from_next;
++to_next;
}
return ok;
}
/*
* This function is used to filter the output
*/
virtual result do_out(state_type& state,
const char* from, const char* from_end, const char*& from_next,
char* to, char* to_limit, char*& to_next ) const
{ /* Write if you need it */ return ok;}
};
int main()
{
// Create a stream (Create the locale) then imbue the stream.
std::ifstream data;
data.imbue(std::locale(data.getloc(), new PunctRemove()));
data.open("X3");
// Now you can use the stream like normal; your locale is replacing the em-dash
// with a normal space.
std::string word;
while(data >> word)
{
std::cout << "Word(" << word << ")\n";
}
}
Now we get:
> ./a.out
Word(He)
Word(was)
Word(young)
Word(perhaps)
Word(from)
Word(twenty-eight)
Word(to)
Word(thirty)
Word(tall)
Word(slender)
I have done a lot of reading on this topic online, and cannot figure out if my code is working. i am working on my phone with the c4droid app, and the debugger is nearly useless as far as i can tell.
as the title says, i need to separate 2 words out of one input. depending on what the first word is, the second may or may not be used. if i do not need the second word everything is fine. if i need and have the second word it works, or seems to. but if i need a second word but only have the first it compiles, but crashes with an out of range exception.
ActionCommand is a vector of strings with 2 elements.
void splitstring(std::string original)
{
std::string
std::istringstream OrigStream(original);
OrigStream >> x;
ActionCommand.at(0) = x;
OrigStream >> x;
ActionCommand.at(1) = x;
return;
}
this code will separate the words right?
any help would be appreciated.
more of the code:
called from main-
void DoAction(Character & Player, room & RoomPlayerIn)
{
ParseAction(Player, GetAction(), RoomPlayerIn);
return;
}
std::string GetAction()
{
std::string action;
std::cout<< ">";
std::cin>>action;
action = Lowercase(action);
return action;
}
maybe Lowercase is the problem.
std::string Lowercase(std::string sourceString)
{
std::string destinationString;
destinationString.resize(sourceString.size());
std::transform(sourceString.begin(), sourceString.end(), destinationString.begin(), ::tolower);
return destinationString;
)
void ParseAction(Character & Player, std::string CommandIn, room & RoomPlayerIn)
(
std::vector<std::string> ActionCommand;
splitstring(CommandIn, ActionCommand);
std::string action = ActionCommand.at(0);
if (ActionCommand.size() >1)
std::string action2 = ActionCommand.at(1);
skipping some ifs
if (action =="wield")
{
if(ActionCommand.size() >1)
DoWield(action2);
else std::cout<<"wield what??"<<std::endl;
return;
}
and splitstring now looks like this
void splitstring(std::string const &original, std::vector<std::string> &ActionCommand)
{
std::string x;
std::istringstream OrigStream(original);
if (OrigStream >>x)
ActionCommand.push_back(x);
else return;
if (OrigStream>>x)
ActionCommand.push_back(x);
return;
}
#include <sstream>
#include <vector>
#include <string>
std::vector<std::string> ActionCommand;
void splitstring(std::string const &original)
{
std::string x;
std::istringstream OrigStream{ original };
if(OrigStream >> x)
ActionCommand.push_back(x);
else return;
if(OrigStream >> x)
ActionCommand.push_back(x);
}
Another idea would be to use the standard library. You can split a string into tokens (using spaces as dividers) with the following function:
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
inline auto tokenize(const std::string &String)
{
auto Stream = std::stringstream(String);
return std::vector<std::string>{std::istream_iterator<std::string>{Stream}, std::istream_iterator<std::string>{}};
}
Here, the result is created in place by using an std::istream_iterator, which basically stands in for the >> operation in your example.
Warning:
This code needs at least c++11 to compile.
Okay, so i have a file that has a string like so:
10/11/12 12:30 PM,67.9,78,98
...
...
I want to separate it like so
10/11/12
12:30 PM
67.9
I know you use getline to separate the comma separated stuff:
getline(infile, my_string, ',')
but I also know that doing this to get the date:
getline(infile, my_string, ' ')
would read in the spaces into my_string
so is there any other way to go about this?
Also, what would I need to do to skip over the last 2 (78,98) and go to the next line? Would just a getline(infile, my_string) suffice?
You can read the string with getline and then use sscanf to read the formatted string :)
Consider using boost libraries that supplement the STL http://www.boost.org/doc/libs/1_57_0/doc/html/string_algo/usage.html
Give your stream a facet that interprets commas as whitespace (which will be our delimiter). Then just make a class that overloads the operator>>() function and leverages this new functionality. istream::ignore is the function use when you want to skip characters.
#include <iostream>
#include <vector>
#include <limits>
struct whitespace : std::ctype<char> {
static const mask* get_table() {
static std::vector<mask> v(classic_table(), classic_table() + table_size);
v[','] |= space; // comma will be classified as whitespace
v[' '] &= ~space; // space will not be classified as whitespace
return &v[0];
}
whitespace(std::size_t refs = 0) : std::ctype<char>(get_table(), false, refs) { }
};
template<class T>
using has_whitespace_locale = T;
struct row {
friend std::istream& operator>>(has_whitespace_locale<std::istream>& is, row& r) {
std::string temp;
is >> r.m_row >> temp;
r.m_row += temp;
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // skip the rest of the line
return is;
}
std::string get_row() const { return m_row; }
private:
std::string m_row;
};
// Test
#include <sstream>
#include <string>
int main() {
std::stringstream ss("10/11/12 12:30 PM,67.9,78,98\n4/24/11 4:52 AM,42.9,59,48");
std::cin.imbue(std::locale(std::cin.getloc(), new whitespace));
row r;
while (ss >> r) {
std::cout << r.get_row() << '\n';
}
}
Coliru Demo
I have to read from a data file which is formatted like this
abcd(string) 1(int) 2(int) 3(int)
abcde(string) 4(int) 3(int) 2(int)
.
.
.
I want to perform some functions which use the variables in the same line only. But here's my code. I'm a beginner so please correct me thank you.
in the .h file
#include <string>
using namespace std;
#ifndef CALC_H
#define CALC_H
class Calc
{
public:
void readFile(string file);
private:
string name;
int a;
int b;
int c;
};
#endif
in the implementation file
#include "Vehicle.h"
#include iostream>
#include fstream>
#include string>
#include cstdlib>
#include cmath>
using namespace std;
void Vehicle::readFile(string filename)
{
ifstream myIn;
int totalNum=0;
myIn.open(filename.c_str());
if (!myIn)
{
cerr<<"Data file failed to open!\n";
exit (0);
}
for (int i=0; i<MAX; i++)
{
while (myIn.peek() != EOF)
{
myIn>>calc[i].name;
myIn>>calc[i].a;
myIn>>calc[i].b;
myIn>>calc[i].c;
totalNum++;
}
}
myIN.close();
and then I want to display what i just read from the file
for (int i = 0; i < MAX; i++)
cout << calc[i].name << calc[i].a << calc[i].b << calc[i].c << endl;
sorry I left out alot of stuff I just want to know if I on the right path. Thanks
The proper way to do this is to overload the >> operator for your class Calc.
class Calc {
public:
friend istream& operator >>(istream& myIn, Calc& calc);
};
istream& operator >>(istream& myIn, Calc& calc) {
myIn >> calc.name;
myIn >> calc.a;
myIn >> calc.b;
myIn >> calc.c;
return myIn;
}
Now you can just do:
while (myIn >> calc[i]) {
++totalNum;
}
You should consider designing it a bit differently.
create a class that holds one line i.e. string int int int - like you have it in "Calc" but without making it dependent on how you create a line (readfile). Lets call it "Line"
class Line
{
public:
std::string name;
int a;
int b;
int c;
};
Now since you need to read several lines you will need some kind of container to hold them, create a vector of Line (or some other container)
std::vector<Line> contents;
then override the stream operator as Tushar suggested so when you read from a file (or from e.g. stdin) you can create instances of Line for each line you read, these instances you use to fill the 'contents' array
now you can start doing whatever it is you want to do with the lines i.e. the actual operation calc
I'm reading a file with C++; the file looks like:
tag1 2345
tag2 3425
tag3 3457
I would like to have something like
input>>must_be("tag1")>>var1>>must_be("tag2")>>var2>>must_be("tag3")>>var3;
Where everything blows up if what's being taken in doesn't match the argument of must_be() and, when done, var1=2345, var2=3425, var3=3457.
Is there a standard way of doing this? (Hopefully where "tag1" need not necessarily be a string, but this is not a requirement.) fscanf from C made it quite easy.
Thanks!
To clarify, each >> reads in one whitespace-delimited set of characters from input. I want to match some of the in-coming blocks of characters (tagX) against strings or data I have specified.
You need to implement operator>> for your class. Something like this :
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
struct A
{
A(const int tag_):tag(tag_),v(0){}
int tag;
int v;
};
#define ASSERT_CHECK( chk, err ) \
if ( !( chk ) ) \
throw std::string(err);
std::istream& operator>>( std::istream & is, A &a )
{
std::string tag;
is >> tag;
ASSERT_CHECK( tag.size() == 4, "tag size" );
std::stringstream ss(std::string(tag.begin()+3,tag.end()));
int tagVal;
ss >> tagVal;
std::cout<<"tag="<<tagVal<<" a.tag="<<a.tag<<std::endl;
ASSERT_CHECK( a.tag == tagVal,"tag value" );
is >> a.v;
return is;
}
int main() {
A a1(1);
A a2(2);
A a3(4);
try{
std::fstream f("in.txt" );
f >> a1 >> a2 >> a3;
}
catch(const std::string &e)
{
std::cout<<e<<std::endl;
}
std::cout<<"a1.v="<<a1.v<<std::endl;
std::cout<<"a2.v="<<a2.v<<std::endl;
std::cout<<"a3.v="<<a3.v<<std::endl;
}
Take a note that for wrong tag value, an exception will be thrown (meaning the tag much match).
Can't you read it line by line, and matching tags for each line? If the tag doesn't match what you expect you just skip the line and move on to the next.
Something like this:
const char *tags[] = {
"tag1",
"tag2",
"tag3",
};
int current_tag = 0; // tag1
const int tag_count = 3; // number of entries in the tags array
std::map<std::string, int> values;
std::string line;
while (current_tag < tag_count && std::getline(input, line))
{
std::istringstream is(line);
std::string tag;
int value;
is >> tag >> value;
if (tag == tags[current_tag])
values[tag] = value;
// else skip line (print error message perhaps?)
current_tag++;
}