Reading one line at a time C++ - c++

I have a file that has strings such as
Hello my name is Joe
How are you doing?
Good you?
I'm trying to output that file as it is, but my program is outputting it as "HellomynameisJoeHowAreyouDoing?Goodyou?" I'm having problems with spaces and new lines.
int main (int argc, char* argv[])
{
index_table table1;
string word;
ifstream fileo;
fileo.open(argv[1]); //where this is the name of the file that is opened
vector<string> line;
while (fileo >> word){
line.push_back(word);
}
cout << word_table << endl;
for (int i=0; i < line.size(); i++)
{
if (find(line.begin(), line.end(), "\n") !=line.end())
cout << "ERRROR\n"; //My attempt at getting rid of new lines. Not working though.
cout << line[i];
}
fileo.close();
return 0;

Just use: std::getline
while (std::getline(fileo, word))
{
line.push_back(word);
}
And then,
for (int i=0; i < line.size(); i++)
{
std::cout<<line[i]<<std::endl;
}
OR simply:-
std::copy(line.begin(), line.end(),
std::ostream_iterator<std::string>(std::cout, "\n") );
//With C++11
for(const auto &l:line)
std::cout<<l<<std::endl;

An alternate solution (with no custom loops):
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
struct line_reader : std::ctype<char>
{
line_reader() : std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
rc['\n'] = std::ctype_base::space;
rc[' '] = std::ctype_base::alpha;
return &rc[0];
}
};
int main()
{
std::ifstream fin("input.txt");
std::vector<std::string> lines;
fin.imbue(std::locale(std::locale(), new line_reader())); // note that locale will try to delete this in the VS implementation
std::copy(std::istream_iterator<std::string>(fin), std::istream_iterator<std::string>(), std::back_inserter(lines));
// file contents now read into lines
fin.close();
// display in console
std::copy(lines.begin(), lines.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}

Related

C++ How to write a code that counts top words while removing any special characters from text file

How do I take a text file from the command line that opens and reads it, and then count the top words in that file but also removes any special characters. I have this code done here and used maps but it isn't counting every word. For instance "hello." is one word and also "$#%hello<>?/". I have this file from the song shake it off that's supposed to read shake 78 times but I only counted 26 in this code.
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
using namespace std;
string ask(const string& msg) {
string ans;
cout << msg;
getline(cin, ans);
return ans;
}
int main() {
ifstream fin( ask("Enter file name: ").c_str() ) ;
if (fin.fail()) {
cerr << "ERROR"; // this is if the file fails to open
return 1;
}
map<string, int> wordCount;
string entity;
while (fin >> entity) {
vector<string> words;
for (int i = 0, a = 0; i < entity.length(); i++) {
char& c = entity[i];
if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z') {
string word = entity.substr(a, i - a);
a = i + 1;
if (word.length() > 0)
words.push_back(word);
}
}
for (auto & word : words)
wordCount[word]++;
}
fin.close();
vector<string> topWords;
const size_t MAX_WORDS = 10;
for ( auto iter = wordCount.begin(); iter != wordCount.end(); iter ++ ) {
int som = 0, lim = topWords.size();
while (som < lim) {
int i = ( som + lim ) / 2;
int count = wordCount[topWords[i]];
if ( iter -> second > count)
lim = i;
else if ( iter -> second < count )
som = i + 1;
else
som = lim = i;
}
if (som < MAX_WORDS ) {
topWords.insert( topWords.begin() + som, iter -> first );
if ( topWords.size() > MAX_WORDS )
topWords.pop_back();
}
}
for (auto & topWord : topWords)
cout << "(" << wordCount[topWord] << ")\t" << topWord << endl;
return 0;
}
One last thing if yall can probably help me on is how would I also write a code that takes a number from the command line alongside the filename and with that number, display the number of top words corresponding with that number passed in the command line, I would assume there is a parse args involved maybe.
Thank you again!
https://s3.amazonaws.com/mimirplatform.production/files/48a9fa64-cddc-4e45-817f-3e16bd7772c2/shake_it_off.txt
!hi!
#hi#
#hi#
$hi$
%hi%
^hi^
&hi&
*hi*
(hi(
)hi)
_hi_
-hi-
+hi+
=hi=
~hi~
`hi`
:hi:
;hi;
'hi'
"hi"
<hi<
>hi>
/hi/
?hi?
{hi{
}hi}
[hi[
]hi]
|hi|
\hi\
bob bob bob bob bob bob bob !###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:":
!###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:": !###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:":
!###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:": !###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:
this is the special character test
Your original code is somewhat hard to refine, I have followed your description to get a program that uses STL.
Combine erase with remove_if to remove unwanted chars
Use set to resort by counts
If you have some experience with Boost, it's a use case with multimap or bimap, which can make the code even more cleaner.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>
using namespace std;
string ask(const string& msg) {
string ans;
cout << msg;
getline(cin, ans);
return ans;
}
int main() {
// ifstream fin(ask("Enter file name: ").c_str());
ifstream fin("shake_it_off.txt");
if (fin.fail()) {
cerr << "ERROR"; // this is if the file fails to open
return 1;
}
map<string, size_t> wordCount;
string entity;
while (fin >> entity) {
entity.erase(std::remove_if(entity.begin(), entity.end(),
[](char ch) { return !isalpha(ch); }),
entity.end());
wordCount[entity] += 1;
}
auto cmp = [](const std::pair<std::string, size_t>& lhs,
const std::pair<std::string, size_t>& rhs) {
return lhs.second > rhs.second;
};
std::multiset<std::pair<std::string, size_t>, decltype(cmp)> top(
wordCount.begin(), wordCount.end(), cmp);
auto it = top.begin();
const size_t MAX_WORDS = 10;
for (size_t i = 0; i < MAX_WORDS && it != top.end(); ++i, ++it) {
cout << "(" << it->first << ")\t" << it->second << endl;
}
return 0;
}

check if a vector contains a substring of another vector

I have file names and I need to check if these files end with any extension of the vector extensions; I would like to use some of the algorithms that are in the library instead of how I have done it, is there any way?
#include <iostream>
#include <algorithm>
#include <vector>
std::string tail(const std::string &st, const size_t len)
{
if (len >= st.size())
return st;
return st.substr(st.size() - len);
}
std::vector<std::string> filtered_files(const std::vector<std::string>& files, const std::vector<std::string>& extensions) {
std::vector<std::string> re;
for(const std::string f : files) {
for(const std::string ex : extensions) {
if(ex == tail(f,ex.size())) {
re.push_back(std::move(f));
break;
}
}
}
return re;
}
int main(int argc, char **argv) {
std::vector<std::string> v{"main.cpp","main.c","main.py"};
std::vector<std::string> re = filtered_files(v,{".c",".cpp"});
for(const std::string s :re) {
std::cout << s << '\n';
}
}
Have a look at the std::find_if() standard algorithm in place of the inner loop. You can use the std::string::compare() method to perform substring comparisons without having to actually allocate new std::string objects, as your loops and tail() function currently do. The only string allocations you need are for the strings pushed into re (and even that allocation can be avoided if you return a std::vector<std::string*> of pointers that point to the strings in te files vector).
Try this:
#include <iostream>
#include <algorithm>
#include <vector>
std::vector<std::string> filtered_files(const std::vector<std::string>& files, const std::vector<std::string>& extensions)
{
std::vector<std::string> re;
for(const std::string &f : files)
{
if (std::find_if(extensions.begin(), extensions.end(),
[&](const std::string &ex){
return (f.size() >= ex.size()) && (f.compare(f.size()-ex.size(), ex.size(), ex) == 0);
}
) != extensions.end())
{
re.push_back(f);
}
}
return re;
}
Live Demo
There are actually many ways of solving this, personally, this is the way I've achieved it before
#include <iostream>
#include <algorithm>
#include <string>
#include <functional>
#include <vector>
int main()
{
std::vector<std::string> v{"main.cpp","main.c","main.py"};
std::vector<std::string> ext{".cpp", ".c"};
std::vector<std::string> res;
for (auto& s : v) {
auto pos = s.find_last_of('.');
if (pos != s.npos) {
char* str = &s[pos];
if (std::any_of(ext.begin(), ext.end(),
[str](const string& a) { return str == a; })) {
res.push_back(s);
}
}
}
for (auto& r : res)
cout << r << endl;
return 0;
}

C++ string help, Spitting a string

I am writing a program which is suppose to be able to open a file, read each line in and separate a LAST NAME, First name: 3 test scores. the format of the file being read is Mark Titan: 80 80 85. I am suppose to output TITAN, Mark: 80 80 85. We are using strings, and so far using my teachers code i have gotten the file to separate completely. it would show the test scores in order from 1-100(100 comes first because it starts with 1 but i can fix that after) and then alphabetically the names. I need help creating a substr of the line, creating a string of just the full name and splitting that into first and last and then sort them correctly. I have been messing with .find but im not sure how to split this vector into smaller vectors. please help and thank you.
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
using namespace std;
void openFile(ifstream &in);
void processFile(ifstream &in, vector<string> &list);
void display(const vector<string> &list);
void sort(vector<string> &list);
int main(int argc, char *argv[])
{
ifstream in;
string line;
vector<string> words;
openFile(in);
processFile(in, words);
display(words);
return 0;
}
void openFile(ifstream &in)
{
string fileName;
bool again;
do
{
again = false;
cout<<"What is the name of the file to you wish to sort? (.txt will be added if no extension is included): ";
cin>>fileName;
if(fileName.find('.') >= fileName.size() )
fileName += ".txt";
in.open(fileName.c_str());
if(in.fail())
{
in.close();
in.clear();
again = true;
cout<<"That file does not exist! Please re-enter"<<endl;
}
}while(again);
}
void processFile(ifstream &in, vector<string> &list)
{
string line, word;
int s1,s2,s3;
stringstream ss;
while(getline(in, line, ':'))
{
ss<<line.substr(line.find(' ') + 1);
while(ss>>word)
list.push_back(word);
ss.clear();
}
sort(list);
}
void sort(vector<string> &list)
{
for(unsigned int i = 0; i < list.size(); ++i)
for(unsigned int j = 0; j < list.size(); ++j)
if(list[i] < list[j])
{
string temp = list[i];
list[i] = list[j];
list[j] = temp;
}
}
void display(const vector<string> &list)
{
cout<<"The file read had "<<list.size()<<" words in it"
<<endl<<"In sorted order, they are:"<<endl;
for(unsigned int i = 0; i < list.size();++i)
cout<<list[i]<<endl;}
You can Tokenize the line twice. First, split on the colon, then split the first token on the space. Also, your teacher will throw empty and malformed lines at you. For instance missing colon or missing name (or missing first/last name). Handle those errors by counting the tokens returned when you split a string or sub string.
void Tokenize(const std::string& theSourceString, std::vector<std::string>& theTokens, const std::string& theDelimiter)
{
// If no delimiter is passed, tokenize on all white space.
if (theDelimiter.empty())
{
std::string aBuffer; // Have a buffer string
std::stringstream ss(theSourceString); // Insert the string into a stream
while (ss >> aBuffer)
{
theTokens.push_back(aBuffer);
}
return; //?
}
// Skip delimiters at beginning.
std::string::size_type aLastPosition = theSourceString.find_first_not_of(theDelimiter, 0);
// Find first "non-delimiter".
std::string::size_type aPosition = theSourceString.find_first_of(theDelimiter, aLastPosition);
while (aPosition != std::string::npos || aLastPosition != std::string::npos)
{
// Found a token, add it to the vector.
theTokens.push_back(theSourceString.substr(aLastPosition, aPosition - aLastPosition));
// Skip delimiters. Note the "not_of"
aLastPosition = theSourceString.find_first_not_of(theDelimiter, aPosition);
// Find next "non-delimiter"
aPosition = theSourceString.find_first_of(theDelimiter, aLastPosition);
}
}
Example use:
std::vector<std::string> tokens;
Tokenize("{ 1, 2, 3, 4, 5 }", tokens, "{}, " );
I have this Utility class that has a bunch of methods for string manipulation. I will show the class function for splitting strings with a delimiter. This class has private constructor so you can not create an instance of this class. All the methods are static methods.
Utility.h
#ifndef UTILITY_H
#define UTILITY_h
// Library Includes Here: vector, string etc.
class Utility {
public:
static std::vector<std::string> splitString( const std::string& strStringToSplit,
const std::string& strDelimiter,
const bool keepEmpty = true );
private:
Utility();
};
Utility.cpp
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit,
const std::string& strDelimiter,
const bool keepEmpty ) {
std::vector<std::string> vResult;
if ( strDelimiter.empty() ) {
vResult.push_back( strStringToSplit );
return vResult;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while ( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !strTemp.empty() ) {
vResult.push_back( strTemp );
}
if ( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return vResult;
}
Main.cpp -- Usage
#include <string>
#include <vector>
#include "Utility.h"
int main() {
std::string myString( "Hello World How Are You Today" );
std::vector<std::string> vStrings = Utility::splitString( myString, " " );
// Check Vector Of Strings
for ( unsigned n = 0; n < vStrings.size(); ++n ) {
std::cout << vStrings[n] << " ";
}
std::cout << std::endl;
// The Delimiter is also not restricted to just a single character
std::string myString2( "Hello, World, How, Are, You, Today" );
// Clear Out Vector
vStrings.clear();
vStrings = Utility::splitString( myString2, ", " ); // Delimiter = Comma & Space
// Test Vector Again
for ( unsigned n = 0; n < vStrings.size(); ++n ) {
std::cout << vStrings[n] << " ";
}
std::cout << std::endl;
return 0;
}

c++ ifstream end of line

I have a file that looks like this:
e r g d g d
f h d r h f
..........
And I want to store these characters in a two-dimensional array
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifstream file("file.txt");
char c[20][20];
int i = 0, j = 0;
while(!file.eof())
{
while(!end of line?)
{
file >> c[i][j];
j++;
}
i++;
}
.....
}
how do i do this?
or how to find number of characters in a line?
You can't use eof() like you do. You have to perform an I/O read operation before you can then use eof().
For what you are attempting, you should use std::getline() instead, eg:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <algorithm>
int main()
{
std::ifstream file("file.txt");
std::string line;
char c[20][20] = {};
for (int i = 0; i < 20; ++i)
{
if (!std::getline(file, line))
break;
std::istringstream iss(line);
for(j = 0; j < 20; ++j)
{
if (!(iss >> c[i][j]))
break;
}
}
...
return 0;
}
That being said, you should consider using std::vector instead of fixed-sized arrays (unless you know for a fact that your file will never exceed 20 lines and/or 20 characters per line):
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iterator>
#include <algorithm>
#include <vector>
int main()
{
std::ifstream file("file.txt");
std::vector<std::vector<char> > c;
std::string line;
while (std::getline(file, line))
{
std::istringstream iss(line);
std::vector<char> tmp;
std::copy(
std::istream_iterator<char>(iss),
std::istream_iterator<char>(),
std::back_inserter(tmp)
);
/* which is equivalent to:
char ch;
while (iss >> ch) {
tmp.push_back(ch);
}
*/
c.push_back(tmp);
}
...
return 0;
}
Alternatively:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iterator>
#include <algorithm>
#include <vector>
typedef std::vector<char> CharVector;
std::istream& operator>>(std::istream &in, CharVector &out)
{
out.clear();
std::string line;
if (std::getline(in, line))
{
std::istringstream iss(line);
std::copy(
std::istream_iterator<char>(iss),
std::istream_iterator<char>(),
std::back_inserter(out)
);
/* which is equivalent to:
char ch;
while (iss >> ch) {
out.push_back(ch);
}
*/
}
return in;
}
int main()
{
std::ifstream file("file.txt");
std::vector<CharVector> c;
std::copy(
std::istream_iterator<CharVector>(file),
std::istream_iterator<CharVector>(),
std::back_inserter(c)
);
/* which is equivalent to:
CharVector cv;
while (file >> cv) {
c.push_back(cv);
}
*/
...
return 0;
}

How to delete characters in a string?

I am trying to write a program hat removes the character 'p' in Pineapple to output the word Pineale. Here is my current code. I found similar problems to this and thought this code would work but it is not unfortunately. Any help is appreciated!
#include <iostream>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <limits>
using namespace std;
int main(){
remove(c,s);
}
string remove(char c, const string & s){
string s = "Pineapple";
char chars[] = "p";
for (unsigned int i = 0; i < strlen(chars); ++i)
{
s.erase(remove(s.begin(), s.end(), chars[i]), s.end());
}
cout << s << endl;
return s;
}
First, you did not define any c or s variables.
Second, your parameter in remove function is const, that means s is unchangeable.
The code below works in my VS2013.
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <limits>
using namespace std;
string remove(char* charToRemove, string &str){
//string s = "Pineapple";
//char chars[] = "p";
for (unsigned int i = 0; i < strlen(charToRemove); ++i)
{
str.erase(remove(str.begin(), str.end(), charToRemove[i]), str.end());
}
cout << str << endl;
return str;
}
int _tmain(int argc, _TCHAR* argv[])
{
string str("Pineapple");
char chars[] = "p";
remove(chars, str);
int i;
cin >>i;
}
Simply get the position of first 'p' from "Pineapple" using string::find(), then use string::erase(). No need to put string::erase() inside the loop.
string remove(char to_rem, string s) {
size_t pos = s.find( to_rem );
s.erase(pos, count(s.begin(), s.end(), to_rem) );
return s;
}
Modified code:
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string remove(char to_rem, string s) {
size_t pos = s.find( to_rem );
s.erase(pos, count(s.begin(), s.end(), to_rem) );
return s;
}
int main() {
cout << remove('p', "Pineapple");
}
Output:
Pineale
Try this:
struct slash_pred
{
char last_char;
slash_pred()
: last_char( '\0' ) // or whatever as long as it's not '/'
{
}
bool operator()(char ch)
{
bool remove = (ch == '/') && (last_char == '/');
last_char = ch;
}
};
path.erase( std::remove_if( path.begin(), path.end(),
slash_pred() ), path.end() );