I am working on a project where I will be able to read in a file that contains any text, like the sample text below. Then, character by character, it will be able to output n-character long sequences (represented below as a read-in value given by the user along the lines of 1, 2, 3, 4...) along the whole length of the text. So, for example:
As Gregor Samsa awoke one morning from uneasy dreams he found himself transformed in his bed into a gigantic insect.
If the user provided 2 as the sequence length, the program should spit out: "As" "s " " G" "Gr" "re" "eg" "go" "or" "r " and so on...
I have written this code but don't know why it won't work. Right now, it doesn't spit out every possible variation of the sequence. Any suggestions would be very helpful. Thanks.
#include "genlib.h"
#include <iostream>
#include <fstream>
#include "simpio.h"
#include "random.h"
#include "vector.h"
#include "map.h"
/* Private Instance Variables */
int seed_length;
string line;
string seed_string;
string next_string;
char ch;
/* Function Prototypes */
string promptUserForFile(ifstream & infile);
int main() {
ifstream infile;
promptUserForFile(infile);
// Ask what order of Markov model to use.
cout << "What order of Markov model should we use? ";
cin >> seed_length;
while (infile.eof() == false) {
ch = infile.get();
for (int i = 0; i < seed_length - 1; i++) {
cout << "ch up here is " << ch << endl;
if (isspace(ch) && i == 0) {
seed_string += ch;
} else {
seed_string += ch;
ch = infile.get();
}
}
next_string = ch;
if (isspace(ch)) {
next_string = " ";
} else {
char trythis = infile.get();
next_string += trythis;
}
cout << seed_string << endl;
cout << next_string << endl;
seed_string = "";
next_string = "";
}
cout << "TEST" << endl;
// Close the file when you're done storing all of the scores.
infile.close();
return 0;
}
string promptUserForFile(ifstream & infile) {
string prompt = "Please input your filename: ";
while(true) {
cout << prompt;
string filename;
getline (cin, filename);
infile.open(filename.c_str());
if(!infile.fail()) return filename;
infile.clear();
cout << "Unable to open that file. Try again." << endl;
if (prompt == "") prompt == "Input file: ";
}
return 0;
}
The code has two problems.
The special handling for isspace is broken:
if (isspace(ch) && i == 0) {
seed_string += ch;
} else {
seed_string += ch;
ch = infile.get();
}
This essentially means that if the first character in this loop is a space, it will be added twice.
Every character received from infile.get() is only added to seed_string once (with the exception of isspace characters).
A better way to code this is to recognize that:
You have to ignore consecutive isspace characters.
Every sequence can be obtained by removing the first character of the preceding sequnce and appending the next character from the file.
Here is a better implementation; it takes the order of the Markov model in the first command line parameter and takes the text from standard input. By encapsulating the skipping of duplicate spaces in a separate function, you don't have to deal with it in the main body of the algorithm.
#include <iostream>
#include <cstdlib>
char next_character() {
static bool was_space = false;
char ret = 0;
do {
ret = std::cin.get();
} while (was_space && std::isspace(ret));
if (std::isspace(ret)) {
was_space = true;
ret = ' ';
} else {
was_space = false;
}
return ret;
}
int main(int argc, char **argv) {
if (argc != 2) return 0;
int mlen = std::atoi(argv[1]);
std::string seq;
for (unsigned i = 0; i < mlen; ++i) {
seq += next_character();
}
std::cout << seq << '\n';
while (true) {
seq.erase(0, 1);
char c = next_character();
if (std::cin.eof()) break;
seq += c;
std::cout << seq << '\n';
}
return 0;
}
Example input:
This is a test
Example output:
This
his i
is is
s is
is a
is a
s a t
a te
a tes
test
Related
How do I read the new line character? I am trying to do a character count, but the new line gets in the way. I tried doing if (text[i] == ' ' && text[i] == '\n') but that didn't work. Here is my repl.it session.
I am trying to read this from file.txt:
i like cats
dogs are also cool
so are orangutans
This is my code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream input;
input.open("file.txt");
int numOfWords = 0;
while (true)
{
string text;
getline(input, text);
for(int i = 0; i < text.length(); i++)
{
if (text[i] == ' ')
{
numOfWords++;
}
}
if (input.fail())
{
break;
}
}
cout << "Number of words: " << numOfWords+1 << endl;
input.close();
}
Your question is asking how to count characters, but your code is counting words instead. std::getline() swallows line breaks. You don't need to worry about them if you want to count words. In fact, you can use operator>> to greatly simplify your counting in that case, eg:
int main()
{
ifstream input("file.txt");
int numOfWords = 0;
string word;
while (input >> word)
++numOfWords;
cout << "Number of words: " << numOfWords << endl;
return 0;
}
If you really want to count characters instead of words, use std::ifstream::get() to read the file 1 character at a time, eg:
int main()
{
ifstream input("file.txt");
int numOfChars = 0;
int numOfWords = 0;
bool isInSpace = true;
char ch;
while (input.get(ch))
{
++numOfChars;
if (std::isspace(ch, input.getloc())) {
isInSpace = true;
}
else if (isInSpace) {
isInSpace = false;
++numOfWords;
}
}
cout << "Number of chars: " << numOfChars << endl;
cout << "Number of words: " << numOfWords << endl;
return 0;
}
I want to print out the first character in the input file is the last character in the output file and vice-versa. But I stuck at how to print out the output.
I need to use arrays. I will read from input file into a character array and the write from the array to the output file.
Example:
Input.txt: A B C D E H
output.txt: H B C D E A
This is my code
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string FileName, FileName2;
string s, temp, FirstChar, LastChar;;
char again = 'Y';
bool close = false;
char MAXSIZE[1024];
while (close == false)
{
cout << "Open the file: ";
cin >> FileName;
ifstream ReadFromFile(FileName);
if (ReadFromFile.is_open())
{
cout << "Succeed to open the file!\n";
// Read character from the input to array
while (!ReadFromFile.eof())
{
ReadFromFile >> MAXSIZE;
cout << MAXSIZE << " ";
}
cout << endl;
cout << "Enter the first character: ";
cin >> FirstChar;
cout << "Enter the last character: ";
cin >> LastChar;
swap(FirstChar, LastChar);
// I stuck at here
ifstream in(FileName);
cout << "Enter a name for a copy file: ";
cin >> FileName2;
ofstream out(FileName2);
while (getline(in, s))
out << s << "\n";
cout << "Close the program and then open your copy file.";
cout << endl << endl;
close = true;
}
else{
cout << "Failed to open the file!\n";
do {
cout << "Do you want to do it again(Y) or Close (N)? ";
cin >> again;
} while (again != 'y' && again != 'Y' && again != 'n' && again != 'N');
if (again == 'y' || again == 'Y')
close = false;
else
close = true;
cout << endl;
}
}
system("pause");
return 0;
}
Your task (according to your explanation) require:
1) reading from input file to array
2) changing the first and the last characters
3) saving array to output file
So, the first and the last characters should not be asked from standard input (keyboard).
#include <iostream>
#include <fstream>
using namespace std;
// filenames can be given as command line arguments
// change the code if you want to read them from standard input
int main(int argc, char* argv[])
{
ifstream inf;
ofstream outf;
size_t counter = 0;
const size_t MAXSIZE = 1024; // MAXSIZE - name of constant
char buffer[MAXSIZE]; // buffer - name of array
// check the command line arguments
// Alternatively you can define: string InpFileName, OutFileName;
// as it is in your code and enter values (cin >>) instead using argv
// if so, you should change inf.open(argv[1]); to inf.open(InpFileName);
// and outf.open(argv[2]); to outf.open(OutFileName);
if (argc != 3)
{
cerr << "Two arguments are required:" << endl
<< " 1) name of existing file (to read)" << endl
<< " 2) name of new file (to create)" << endl;
return 1;
}
// open files
inf.open(argv[1]);
outf.open(argv[2]);
// check files
if (!inf.is_open() || !outf.is_open())
{
cout << "ERROR: some trouble with files." << endl;
return 2; // stop the program
}
// process
// 1) reading
while (counter < MAXSIZE){
buffer[counter] = inf.get();
if (buffer[counter] != EOF)
{
counter++;
}
else
{
counter--; // the last character is not valid
break; // end of file
}
}
// 2) changing
char b = buffer[counter];
buffer[counter] = buffer[0];
buffer[0] = b;
// 3) output
for (int i = 0; i <= counter; i++)
{
outf.put(buffer[i]);
}
// close files
inf.close();
outf.close();
return 0;
}
UPDATE:
Clarify the task for cases when some unprintable character (like space) is the first or the last
Looks like a homework problem for a C++ class. One hint which may help is to
divide the file into blocks of X bytes and read the blocks in reverse order....
std::istream::seekg
I am currently trying to build a program that reads in a file, scans through that file, and outputs all words in that file surrounded by " marks. I am currently stumped and was hoping to get some help!
#include <iostream>
// For file I/O:
#include <fstream>
#include <cstdlib>
#include <iomanip>
using namespace std;
// Prototype the count function so we can have it below it's first
// use in main().
void count(istream& in, int& lines, int& words, int& characters);
/*
* wc <filename>
*/
int main(int argc, char *argv[])
{
if (argc < 2) {
cerr << "Usage: wc <filename>" << endl;
return 0;
}
// Open the file specified by argv[1] for reading:
// Constructs a ifstream object called "in":
ifstream in(argv[1]);
// Was there a problem opening the file?
if (!in.good()) {
cerr << "Unable to open file [" << argv[1] << "] for reading." << endl;
return 1;
}
int lines = 0, words = 0, characters = 0;
count(in, lines, words, characters);
cout << setw(5) << lines << " " << words << " " <<
characters << " " << argv[1] << endl;
// Close the input stream:
in.close();
}
void count(istream& in, int& lines, int& words, int& characters)
{
int i;
char s;
int ch;
bool inword = false;
// Read until the end of file is reached, or there was an error:
while (!in.eof()) {
// Read a character from the input stream "in":
s = in.get(); //Set char s = in.get
for(i=0; s != 0; i++){ //Loop to iterate through the characters
while(s == '"'){ //While s is equal "
cout << s << endl; // Print s
if(s == '"') // If we hit another ", then we break
break;
}
}
if (in.good() == false) return;
characters++;
if (!isspace(ch) && !inword) {
inword = true;
words++;
} else if (isspace(ch) && inword) {
inword = false;
}
if (ch == '\n') lines++;
}
}
your algorithm seems wrong.. in the for loop you compare to 's' but you're not updating it... try something like this in your main loop(QnD):
while (!in.eof() && (s = in.get()) != '"'); // read to first quote char
/* this is the word we want.. run to end quote marks.. */
while (!in.eof() && (s = in.get()) != '"') {
cout << s;
}
cout << endl;
I found so incredibly many question posts of this sort - i'm speaking of "convert string to char array" - but none of those solutions actually work for me, trying to convert cin >> text into some char array textArray[1024] which I could then convert into a list cause I think it's easier to work with.
The Problem is: Spaces. Every time when there's a space in there, it just skips the following actions and punches me with my own error messeges.
It's for some encryptor (code down below).
If there's any easier way of doing this then let me know.
#include <iostream>
#include <string>
#include <fstream>
#include <list>
#include "encryptor.h"
using namespace std;
void encrypt()
{
string text;
char textArray[1024];
list<char> listText;
list<char>::iterator it;
int textSize;
string code;
bool fail = false;
string segment;
string fileName;
cout << "Now enter your text. (max 1024 chars)" << endl;
cin >> text;
textSize = text.size();
//string to char[]
//none of these work
strncpy(textArray, text.c_str(), sizeof(textArray));
textArray[sizeof(text) - 1] = 0;
strcpy_s(textArray, text.c_str());
for (int i = 0; i < text.length(); i++)
{
textArray[i] = text[i];
}
aText[text.length()] = '\0';
text.copy(textArray, text.length()+1);
//char[] to list
for(int i = 0; i < textSize; i++)
{
char *c = new char(textArray[i]);
listText.push_back(*c);
}
//Going through list
//for every char there's a special segment added to the string
for(it = listText.begin(); it != listText.end(); it++)
{
if(fail == true) break;
switch (*it)
{
case 'a':
case 'A':
{
segment = "XQ7";
} break;
{/*---*/} //I just let everything from b - z and 0 - 9 out for this post
case ' ':
{
segment = "Z 7";
} break;
case '.':
{
segment = "Z 8";
} break;
case ',':
{
segment = "Z 4";
} break;
default:
{
cout << "There's a special char this program doesn't understand. It is "
cout << *it << endl;
cout << "Do it again" << endl;
fail = true;
} break;
}
code = code + segment;
}
do
{
cout << "\n\nname of the file: ";
cin >> fileName;
if(fileName != "")
{
ofstream write;
write.open(fileName + ".txt");
write << code;
write.close();
} else {
cout << "Name shouldn't be empty!" << endl;
}
} while(fileName == "");
}
Your main issue is not in converting the string text to a character array but it is that you are not capturing the entire line from stdin.
The line cin >> text; will read from stdin until the first whitespace character has been met. That is why you are having issues with spaces. You are only reading characters into text up to the first whitespace character. Instead you need to use getline(). Replacing cin >> text; with getline(cin, text); will read in an entire line from stdin including any whitespace characters.
I've included a complete example to read in a line of text from stdin and convert it to a list of characters for you below. It completely skips the need to convert the string into a character array before converting it into a list.
#include <iostream>
#include <list>
#include <string>
using namespace std;
int main() {
string s;
list<char> text;
getline(cin, s);
for (string::iterator it = s.begin(); it != s.end(); ++it) {
text.push_back(*it);
}
// Verification
cout << "You entered " << text.size() << " characters\nThey were:\n";
for (list<char>::iterator it = text.begin(); it != text.end(); ++it) {
cout << *it;
}
cout << endl;
}
Here is my runnable code:
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char **argv) {
if (argc > 1) { // passed in parameter
ifstream file(argv[1]); // create file from second parameter
string line;
if (file) { // file exists and has been opened
//stack *stmt = new stack();
while (getline(file, line)) { // run through lines of file
string word = "";
cout << "LINE: " << line << endl;
for (int i = 0; i < line.length(); i++) { // run through char of line
char ch = line[i];
if (ch == ' ') {
if (word == "") {
continue;
} else {
//stmt->push(word);
cout << "\x1b[34;1mWORD: " << word << "\x1b[0m" << end;
word = "";
}
} else {
word += ch;
}
}
}
cout << stmt->size() << endl;
while (stmt->has_next()) {
cout << stmt->pop() << endl;
}
} else {
cerr << "\x1b[31;1mNo such file, \x1b[21m" << argv[1] << "\x1b[0m" << endl;
}
} else { // no parameters passed in
cerr << "\x1b[31;1mYou did not specify any files to parse\x1b[0m" << endl;
}
return 0;
}
It seems straight forward. However, when the character, ch, is the character for an integer (like '0' to '9'), the character simply is not appended.
Does this happen with you guys (if you create a test file like so:
this is from line 1
line 2
3
and then after g++ test.cpp - if you name file test.cpp - and ./a.out test - if you store the above test file to test - you will see (frustratingly so) that WORD: ... (in blue) never contains a number if the number is a single character.
I.E. OUTPUT for me:
LINE: this is from line 1
WORD: this
WORD: is
WORD: from
WORD: line
LINE: line 2
WORD: line
LINE: 3
This is very frustrating; please help and explain why it is not working or comment that it works for you.
It seems that words are printed only if there is a space after them:
if (ch == ' ') {
....
cout << "\x1b[34;1mWORD: " << word << "\x1b[0m" << end;
....
}
This is not the case for the numbers in the given test.