I am working on a project for a basic programming class and am not entirely familiar with strings and all. The goal of the program is to take one simple text file with a few random, repeated words, and return a file with each separate word and the number of times it appears in the file. The input file looks something like
Class
Text
Class
fall
mark
mark
Text
and the output should read,
Class 2
Text 2
fall 1
mark 2
I am having trouble reading and setting up an array for the input data. Not sure exactly how to set it up. Any suggestions would be great.
int main(void)
{
int k=0, p=0, words=0, match=0, ch=0;
double xx;
char I[WORD][LETTER;
FILE *file;
file = fopen("C:\\Users\\Andrew\\Documents\\te2.txt", "r");
if(file != NULL){
// Count the amount of words in file set up array
int i=0, j=0;
for(i=0; i<WORD; i++){
for(j=0; j<LETTER; j++){
fscanf(file, "%s", &I[i][j]);
ch++;
}}
What you are trying to do is really quite simple. Lets break it down:
Read in each word in a file.
Store it in something that recognises individual words and can increment a number (a std::map).
Print out the result.
Part 1 - Read each word
Lets read in a file word by word. Searching read in a file word by word c++ would have sufficed but here is a short example:
ifstream file; // A in file stream, the c++ way of reading files.
file.open ("example.txt");
string word; // A word to store each word.
// Read each word.
while ( file >> word) {
// Do something with your word. (Part 2)
}
Its as easy as that!
Part 2 - Store them in a map
Now we want to have a map, this is because a map will store only unique words and we can use its value to count the number of each unique word. Read about maps here. We need a string as the key and an int to count the words, so:
std::map<std::string, int> myWords;
To put them in, we need to check if the word already exists, otherwise we set it to one:
// See if the map already contains the word (not only is this easy, it is also very efficient!)
// If we dont contain the word then we get an iterator to past the end of the map.
if (myWords.find(word) == myWords.end()) {
myWords[word] = 1; // If our map doesn't already have this word
// we have encountered our first!
} else {
myWords[word]++; // The map already has the word so just increment it.
}
Part 3 - Print them out
The easy part, simply iterate over the map and print them out:
for (auto wordPair : myWords) {
std::cout << wordPair.first << " " << wordPair.second << std::endl;
}
Put it all together
And you get this:
http://ideone.com/TCMOKh
So I have been working on it and I came up with the idea to have the data come in character by character withfscanf(file, "%c", &array[]);and i have been working on an algorithm to set a certain amount of the characters before a '\n' into a smaller array to use it tom compare to the full string. in the file i have added spaces to any word that was a few characters so that the "word sizes are all the same with the spaces, the arrays are successful just having some issues witht the algorithm itself.
`
#include <stdio.h>
#include <cctype>
#define Words 9
#define Letters 6
#define CHARACT Words*Letters
#define CORRECT 3
int main(void){
double xx;
int match=0, indx=0, i=0, k=0, j=0, b, read=0, r, t, track=0;
char shrt[Letters], Long[CHARACT], c;
FILE *file;
file =fopen("C:\\Users\\Andrew\\Documents\\te2.txt", "r");
if(file != NULL)
{
// initialize long string (full file by characters)
for(k=0; k<CHARACT; k++)
{
fscanf(file, "%c", &Long[k]);
}
// set up shrt[] to compare to rest of array
while(track <= CHARACT)
{
indx+=track;
//STEP 1: take shrt[] out of Long[] for comparisons
for(r=0; r<Letters; r++)
{
shrt[r] = Long[indx];
indx++;
if(shrt[r] == '\n')
break;
}
for(t=0; t<CHARACT; t++)
{
match=0;
int VV = track*Letters;
// STEP 2: keep shrt[] constant, compare to full string one by one
for(int p=0; p<Letters-2; p++)
{
if(shrt[p] == Long[VV])
{
match++;
}
}
if(match >= CORRECT)
{
for(int ee=0; ee<Letters; ee++)
{
printf("%c", shrt[ee]);
}
printf(" %i", match);
}
track+=Letters;
}
}// big for loop
// TESTING TESTING
printf("\n\n\nTEST\n\n");
for(k=0; k<CHARACT; k++)
printf("%c", Long[k]); // delete when ready
printf("%i", read);
}// big if
else{
printf("error");
}
fclose(file);
scanf("%f", &xx);
return 0;
}`
Related
I am attempting to read a text file of characters into a character array (char array[MAX_ROW][MAX_COL]) and the text file has less rows and columns than the character array. This leads to a problem of reading past the substance material that is within the text file. I run into this problem when I read in using the following method:
ifstream whiteboard; //ifstream object for reading from a file.
whiteboard.open(board_name.c_str());
for(int i = 0; i < MAXROW; i++){ //naive read for canvas, not considering the /n characters or the size of the image.txt
for(int j = 0; j < MAXCOL; j++){ //for this to store the print properly it must be the exact size of the image dimensions
canvas[i][j] = whiteboard.get();
if(whiteboard.get() == '/n'){
return;
}
else if(whiteboard.get() != '/n'){
canvas[i][j] = whiteboard.get();
}
}
}
whiteboard.close();
The code above is supposed to run through the 2d array only to the point where the '/n' character is. Thus, allowing me to enter an array of any size. The newline character is at the end of each line of text in a text file (in the form of an enter keystroke). The read to file stops when a newline has been read. However, I am having issues implementing this correctly. Does anyone have any hints that may help me see this more clearly? Thank you very much!
EDIT:
Input File
xxxxxxxxxxxxxx
x x
x x
x x
x x
x x
xxxxxxxxxxxxxx
I am hoping to input the box above (along with all of its ' ' characters contained within it) into corresponding values of the character array. I wish to stop the read after reading the rightmost column of x's in and after reading the final x (the bottom right). You can see that my problem comes from having an array that is larger than the size of my text box here. I understand I could fix this by equating the character array to have the same dimensions as the text box, but I wish to keep a large enough constant so that I can read in a file of a relatively large size.
I have one solution, do the following:
int n=1025, m=1024, MAX_LINES=1025, i=0, j=0;
char character, Matrix[n][m];
fstream file;
file.open("file.txt", ios::in);
while (file.get(character))// loop executes until the get() function is able to read contents or characters from the file
{
Matrix[n][m]=character; // copy the content of character to matrix[n][m], here n is used to work as lines and m as normal arrays.
m++; // finished copying to matrix[n][m] then m++ else the program will overwrite the contents to the same array.
If (m>=1024)// if string[n][m] reached the limit which is 1024.
{
Matrix[n][m]='\0'; //termimate that line
m=0;// start with a new column
if (n<MAX_LINES)// if n is less than 1024 then
n++;// write to a next line because m can support only 1024 chars.
}
Matrix[n][m]='\0';// this will terminate the whole string not just one line.
file.close();
The Matrix Arrays is filled until the file has contents, but less than 1024x1024 chars, u can increase the chars input from the file but i face problems when taking inn more than 4 kb of data into Matrix...
I hope this helps u, if helps even a bit then +1 vote to my answer pls...
You are looking for something like this:
ifstream whiteboard;
whiteboard.open(board_name);
if ( !whiteboard.is_open() )
{
// do something here...
}
char c;
int row = 0, col = 0;
while ( whiteboard.get( c ) )
{
if ( c == '\n' )
{
row++;
col = 0;
continue;
}
canvas[ row ][ col++ ] = *reinterpret_cast< unsigned char * >( &c );
}
whiteboard.close();
With this code you can fill up your matrix with the content of the file... always supposing the "array" in the file fits in the array canvas[][]
If you aren't restricted to using an array, I wanted to add an alternative solution that would allow your canvas to be dynamically sized.
using std::vector;
std::ifstream whiteboard(board_name);
vector<vector<char>> canvas;
canvas.emplace_back();
// ^ Replace with push_back(vector<char>()); if not using C++11
char c;
while (whiteboard.get(c)) {
if (c == '\n') {
canvas.emplace_back(); // See above
}
else {
canvas.back().push_back(c);
}
}
You can decide to iterate through your canvas by using either range-based for loops or by using an index (iterators work too but are ugly):
// Loop through using range-based for (C++11)
for (auto& row : canvas) {
for (auto& col : row) {
std::cout << col;
}
std::cout << std::endl;
}
// Loop through using index
for (int i = 0; i < canvas.size(); i++) {
for (int j = 0; j < canvas[i].size(); j++) {
std::cout << canvas[i][j];
}
std::cout << std::endl;
}
How can i transfer a text file(.txt) to array 2D in c++ and this is my source code
fstream fin('textfile.txt', ios::in);
int matrix[n][m]; // n is the number of rows and m is the number of columns
for(int i = 0;i < n; i++){
for(int j = 0; j<m; j++){
fin>>matrix[i][j];
}
}
but how can i detemine n and m for do this,i need your help and your advice, please Join us your perspectives
This solution requires C++11+
If there is no n & m in the file, you must assume that the layout is also in 2D
One Two Three
Four Five Six
Warning:: Untested code.
std::stringstream res;
std::string wordUp;
std::vector<std::string> str;
// the matrix, vector of vector of strings.
std::vector<std::vector<std::string>> matrix;
fstream fin('textfile.txt', ios::in);
int lines = 0;
int words = 0;
// read the file line by line using `getline`
for (std::string line; std::getline(fin, line); ) {
++lines;
// use stringstream to count the number of words (m).
res.str(line); // assign line to res. might also need some reset of good().
while (res.good()) {
res >> wordUp;
str.push_back(wordUp);
++words;
}
matrix.push_back(str);
str.erase(str.begin());
}
So u mean u want to read a file and copy contents to char Matrix[][]??, you can use while loop to read characters, and split every 1024 bytes(1 kb) by lines, i mean do this:
#include <fstream.h>
int main()
{
int n=0, m=0, MAX_LINES=1025, i=0, j=0;
char character, Matrix[1024][1025];
fstream file;
file.open("file.txt", ios::in);
while (file.get(character))// loop executes until the get() function is able to read contents or characters from the file
{
Matrix[n][m]=character; // copy the content of character to matrix[n][m], here n is used to work as lines and m as normal arrays.
m++; // finished copying to matrix[n][m] then m++ else the program will overwrite the contents to the same array.
If (m>=1024)// if string[n][m] reached the limit which is 1024.
{
Matrix[n][m]='\0'; //termimate that line
m=0;// start with a new column
if (n<MAX_LINES)// if n is less than 1024 then
n++;// write to a next line because m can support only 1024 chars.
}
}
Matrix[n][m]='\0';// this will terminate the whole string not just one line.
file.close();
for (i=0; i<1025; i++)
{
for (j=0; j<=1024 || Matrix[i][j]!='\0'; j++)
cout<<Matrix[i][j];
}
return 0;
}
This code will read 1024×1024 chars, but if the txt file is less than 1024(m) characters, the while loop will be exited and Matrix[n][m]='\0'; statement is executed.
EDIT: As asked by David i have written the whole code with main() sorry bro i forget, the bug in the code was the variables n and m were intialised to 1025 and 1024 so the program skips writing to Matrix as the Matrix[1024][1025] cannot store more characters... I think this would help, ok bro...
I am using two dynamic arrays to read from a file. They are to keep track of each word and the amount of times it appears. If it has already appeared, I must keep track in one array and not add it into the other array since it already exists. However, I am getting blank spaces in my array when I meet a duplicate. I think its because my pointer continues to advance, but really it shouldn't. I do not know how to combat this. The only way I have was to use a continue; when I print out the results if the array content = ""; if (*(words + i) == "") continue;. This basically ignores those blanks in the array. But I think that is messy. I just want to figure out how to move the pointer back in this method. words and frequency are my dynamic arrays.
I would like guidance in what my problem is, rather than solutions.
I have now changed my outer loop to be a while loop, and only increment when I have found the word. Thank you WhozCraig and poljpocket.
Now this occurs.
Instead of incrementing your loop variable [i] every loop, you need to only increment it when a NEW word is found [i.e. not one already in the words array].
Also, you're wasting time in your inner loop by looping through your entire words array, since words will only exist up to index i.
int idx = 0;
while (file >> hold && idx < count) {
if (!valid_word(hold)) {
continue;
}
// You don't need to check past idx because you
// only have <idx> words so far.
for (int i = 0; i < idx; i++) {
if (toLower(words[i]) == toLower(hold)) {
frequency[i]++;
isFound = true;
break;
}
}
if (!isFound) {
words[idx] = hold;
frequency[idx] = 1;
idx++;
}
isFound = false;
}
First, to address your code, this is what it should probably look like. Note how we only increment i as we add words, and we only ever scan the words we've already added for duplicates. Note also how the first pass will skip the j-loop entirely and simply insert the first word with a frequency of 1.
void addWords(const std::string& fname, int count, string *words, int *frequency)
{
std::ifstream file(fname);
std::string hold;
int i = 0;
while (i < count && (file >> hold))
{
int j = 0;
for (; j<i; ++j)
{
if (toLower(words[j]) == toLower(hold))
{
// found a duplicate at j
++frequency[j];
break;
}
}
if (j == i)
{
// didn't find a duplicate
words[i] = hold;
frequency[i] = 1;
++i;
}
}
}
Second, to really address your code, this is what it should actually look like:
#include <iostream>
#include <fstream>
#include <map>
#include <string>
//
// Your implementation of toLower() goes here.
//
typedef std::map<std::string, unsigned int> WordMap;
WordMap addWords(const std::string& fname)
{
WordMap words;
std::ifstream inf(fname);
std::string word;
while (inf >> word)
++words[toLower(word)];
return words;
}
If it isn't obvious by now how a std::map<> makes this task easier, it never will be.
check out SEEK_CUR(). If you want to set the cursor back
The problem is a logical one, consider several situations:
Your algorithm does not find the current word. It is inserted at position i of your arrays.
Your algorithm does find the word. The frequency of the word is incremented along with i, which leaves you with blank entries in your arrays whenever there's a word which is already present.
To conclude, 1 works as expected but 2 doesn't.
My advice is that you don't rely on for loops to traverse the string but use a "get-next-until-end" approach which uses a while loop. With this, you can track your next insertion point and thus get rid of the blank entries.
int currentCount = 0;
while (file)
{
// your inner for loop
if (!found)
{
*(words + currentCount) = hold;
*(frequency + currentCount) = 1;
currentCount++;
}
}
Why not use a std::map?
void collect( std::string name, std::map<std::string,int> & freq ){
std::ifstream file;
file.open(name.c_str(), std::ifstream::in );
std::string word;
while( true ){
file >> word; // add toLower
if( file.eof() ) break;
freq[word]++;
}
file.close();
}
The problem with your solution is the use of count in the inner loop where you look for duplicates. You'll need another variable, say nocc, initially 0, used as limit in the inner loop and incremented whenever you add another word that hasn't been seen yet.
I cannot for the life of me figure out why this doesn't work. I'm having to do a frequency check of a list of words from a file, and when reading them in I'm trying to check the current word against the elements in the string array, and making sure they're not equal before I add it. Here's the code:
fin.open(finFile, fstream::in);
if(fin.is_open()) {
int wordArrSize;
while(!fin.eof()) {
char buffer[49]; //Max number chars of any given word in the file
wordArrSize = words.length();
fin >> buffer;
if(wordArrSize == 0) words.push_back(buffer);
for(int i = 0; i < wordArrSize; i++) { //Check the read-in word against the array
if(strcmp(words.at(i), buffer) != 0) { //If not equal, add to array
words.push_back(buffer);
break;
}
}
totNumWords++; //Keeps track of the total number of words in the file
}
fin.close();
This is for a school project. We're not allowed to use any container classes so I built a structure to handle expanding the char** array, pushing back and popping out elements, etc.
for(int i = 0; i < wordArrSize; i++) { //this part is just fine
if(strcmp(words.at(i), buffer) != 0) { //here lies the problem
words.push_back(buffer);
break;
}
}
You will enter your if statement each time the current word doesn't match the ith word in the array. So, most of the times, it will be the very first iteration when you will enter the loop. This means that in the beginning of the cycle (on the first word inside your string list that doesn't match the buffer) you will add the buffer to the string list and break the cycle.
What you should do is finish checking the whole words array, and only then add the buffer into the array. So you should have something like this:
bool bufferIsInTheArray = false;//assume that the buffered word is not in the array.
for(int i = 0; i < wordArrSize; i++) {
if(strcmp(words.at(i), buffer) == 0) {
//if we found a MATCH, we set the flag to true
//and break the cycle (because since we found a match already
//there is no point to continue checking)
bufferIsInTheArray = true;
break;
}
//if the flag is false here, that means we did not find a match in the array, and
//should add the buffer to it.
if( bufferIsInTheArray == false )
words.push_back(buffer);
}
i think your code words.push_back(buffer); should come outside the for loop.
Put a flag to check if you found the buffer in array inside for loop and according to flag add it to array outside the for loop
I am making a Sudoku program and my i have a test.txt file that reads
53__7____
6__195___
_98____6_
8___6___3
4__8_3__1
7___2___6
_6____28_
___419__5
____8__79
where the "_" are actually spaces. The reason i give you _ is so you can see that there are literally only 9 characters on each line.
I was thinking that I would have to do something like having GRID[row][column], however I frankly don't know what types I should put my arrays as and I am just lost.
I simply want to make it so when i want to output say GRID[0][0] it returns 5, while if i ask for GRID[0][3] it returns a ' '.
It is getting it so the array store both the numbers and the spaces is where i am getting completely lost
What I currently have tried so far:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.is_open())
{
while(myfile.good())
{
getline(myfile, line);
cout << sudoku_grid[line] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
it returns the error line 12: no match for 'operator [ ]' in 'sudoku_grid[line]'
Here is my attempt though guidelines through you guys:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.good())
{
for(int i = 0; i < 9; i++)
{
getline(myfile, line);
for(int j = 0; j < 9; j++)
{
if (line[j] == ' ')
sudoku_grid[j][i] = -1;
else sudoku_grid[j][i] = line[i];
}
cout << sudoku_grid[i] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
The result is a very awkward answer of strange letters and a new numbers.
I'll just give you the algorithm/logic, not going to write the code for you. Try it and come back when stuck.
Initialize output in memory 2D array: numbers[9][9]
Open the file
Until there is no line left in the file:
a. Get the line i
b. Until there are no more characters in the line:
b1. Get each character of the line c
b2. If the character is not space, then numbers[i]=c, else numbers[i]=-1
Your array can be made up of int and in b2 if a whitespace is encountered you can insert -1 to indicate the absence of a number. Of course your code manipulating numbers array needs to take that into account.
Since you need to store both chars and integer type values, use char. each of your integer lies in the range 0-9, so can be stored as a character.
char Grid[9][9];
now you can read each character from the string and store it in the array. It will not only keep your spaces intact but also each character. Always remember to use ASCII codes to access the elements of the grid. For 0-9, ASCII codes are 48-57, ASCII code for space is 32.
Hope it helps...
Edit code: Here is the simplest example... PLace your test file in d:, or edit the path of file in code
int main (void)
{
FILE *fp = fopen("d:\\test.txt","r");
char sudoku_grid[9][9], ch;
// I am assuming that file is valid and data in that is also valid
if(fp)
{
for(int i = 0; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
//too read each character
ch = fgetc(fp);
sudoku_grid[i][j] = ch;
}
// to read '\n' from the line
ch = fgetc(fp);
}
//for checking if data went correctly
for(int i = 0; i< 9;i++)
{
for(int j= 0; j<9;j++)
cout<<sudoku_grid[i][j];
cout<<endl;
}
}
return 0;
}
In the first code you get the error message because sudoku_grid can
only be indexed by numbers and not by strings.
In the second code the line
sudoku_grid[j][i] = line[i];
should probably be
sudoku_grid[j][i] = line[j];
Does this answer your question?