C++ Vector iteration failing for single element input - c++

I am trying to get a txt file with entries part1/1 part2/4 etc... from user and store in vectors "part_name" and "rev_id". So "part_name" contains part1 part2 ... and "rev_id" contains 1 4.....
The program is run as program.exe list.txt in command prompt.
The program works fine when the txt file has 2 or more inputs , but when it has single input the vector size is shown as 2 (but must be 1).
i.e.
if list.txt contains part1/1 part2/4 => part_name.size() is 2
if list.txt contains part1/1 => part_name.size() is still 2.
Can someone help me resolve this ?
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
int main(int argc, char*argv[])
{
std::string s ;
std::string delimiter = "/";
size_t pos;
std::vector<std::string> part_name;
std::vector<std::string> rev_id;
std::string token1,token2;
ifstream readFile (argv[1]);
if (readFile.is_open())
{
while (!readFile.eof())
{
readFile >> s;
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{
token1 = s.substr(0, s.find(delimiter));
token2 = s.substr(pos + delimiter.length());
part_name.push_back(token1);
rev_id.push_back(token2);
}
}
}
else{
std::cout<<"Cannot open file"<<endl;
}
readFile.close();
for (unsigned j=0; j < part_name.size(); j++)
{
cout<<part_name.size()<<endl;
cout<<"part name j is " <<part_name[j]<<endl;
cout<<"part id j is " <<rev_id[j]<<endl;
}
}

I think the problem lies here
while (!readFile.eof())
{
readFile >> s;
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{
token1 = s.substr(0, s.find(delimiter));
token2 = s.substr(pos + delimiter.length());
part_name.push_back(token1);
rev_id.push_back(token2);
}
change above to
while (readFile >> s)
{
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{
token1 = s.substr(0, s.find(delimiter));
token2 = s.substr(pos + delimiter.length());
part_name.push_back(token1);
rev_id.push_back(token2);
}

Your last read is probably not reading anything. Try:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
int main(int argc, char*argv[])
{
std::string s ;
std::string delimiter = "/";
size_t pos;
std::vector<std::string> part_name;
std::vector<std::string> rev_id;
std::string token1,token2;
ifstream readFile (argv[1]);
if (readFile.is_open())
{
while( ( readFile >> s ).good() )
{
std::cerr << "Field '" << s << "' and " << readFile.good() << std::endl;
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{
token1 = s.substr(0, pos);
token2 = s.substr(pos + delimiter.length());
part_name.push_back(token1);
rev_id.push_back(token2);
}
}
}
else {
std::cout<<"Cannot open file"<<endl;
}
readFile.close();
for (unsigned j=0; j < part_name.size(); j++)
{
cout<<part_name.size()<<endl;
cout<<"part name j is " <<part_name[j]<<endl;
cout<<"part id j is " <<rev_id[j]<<endl;
}
}

eof() returns true not when the file position is at the end, but after you attempt a read at the end of the file. So the first time in the loop you consume the input up to the eof (not included). Now eof() is false. For this reason the loop is entered again and this time the extractor (>>) hits the end of file. The read operation fails and the string is not changed (that's why you see the same values twice).
A better (and more idiomatic to modern C++) way to code is by using stream iterators
#include <iterator>
// [...]
std::istream_iterator<std::string> scan( readFile );
std::istream_iteartor<std::string> eof;
while( scan != eof )
{
s = *scan++;
// s is your string
}
Also it would be better to have the loop in the second part to run from 0 upward, since elements in vectors are numbered starting from 0.

There are some lines than make me suspicious..
Why start your iteration loop by the index 1 ?
for (unsigned j=1; j < part_name.size(); j++)
{
cout<<part_name.size()<<endl;
cout<<"part name j is " <<part_name[j]<<endl;
cout<<"part id j is " <<rev_id[j]<<endl;
}
You always skip the first element of yours vectors.

Related

arrange line in txt file in ASCII order using array and display them

#include <stdio.h>
#include <string.h>
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ifstream infile; // ifstream is reading file
infile.open("read.txt"); // read.txt is the file we need to read
std::cout << infile;
string str;
if (infile.is_open()) {
while (getline(infile, str)) {
char str[2000], ch;
int i, j, len;
len = strlen(str);
for (i = 0; i < len; i++) {
for (j = 0; j < (len - 1); j++) {
if (str[j] > str[j + 1]) {
ch = str[j];
str[j] = str[j + 1];
str[j + 1] = ch;
}
}
}
}
cout << "\nProcessed data:" << str;
}
return 0;
}
My txt file:
Today is a fine day.
It’s sunny.
Let us go out now!
My result should be:
.Taaaddefiinosyy
’.Innsstuy
!Legnooosttuuw
Spaces is consider here as well.
I'm new to C++.
I need some pros help.
Thank you very much!
Making use of the STL:
Read your file line by line into a std::string using std::getline.
Sort every line using std::ranges::sort.
Print it.
The example below:
also uses the fmt library instead of std::cout, and
reads from a std::istringstream instead of a std::ifstream.
[Demo]
#include <algorithm> // sort
#include <fmt/core.h>
#include <sstream> // istringstream
#include <string> // getline
int main() {
std::istringstream iss{
"Today is a fine day.\n"
"It's sunny.\n"
"Let us go out now!\n"
};
fmt::print("Original file:\n{}\n", iss.str());
fmt::print("Processed file:\n");
std::string line{};
while (std::getline(iss, line)) {
std::ranges::sort(line);
fmt::print("{}\n", line);
}
}
// Outputs:
//
// Original file:
// Today is a fine day.
// It's sunny.
// Let us go out now!
//
// Processed file:
// .Taaaddefiinosyy
// '.Innsstuy
// !Legnooosttuuw
Your code does not work, because:
The line std::cout << infile; is wrong. If you want to print the result of istream::operator bool() in order to determine whether the file was successfully opened, then you should write std::cout << infile.operator bool(); or std::cout << static_cast<bool>(infile); instead. However, it would probably be better to simply write std::cout << infile.fail(); or std::cout << !infile.fail();.
The function std::strlen requires as a parameter a pointer to a valid string. Maybe you intended to write str.length()? In that case, you should delete the declaration char str[2000], because it shadows the declaration string str;.
You should print the sorted result immediately after sorting it, before it gets overwritten by the next line. Currently you are only printing the content str a single time at the end of your program, so you are only printing the last line.
After performing the fixes mentioned above, your code should look like this:
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ifstream infile; // ifstream is reading file
infile.open("read.txt"); // read.txt is the file we need to read
std::cout << infile.fail();
string str;
if (infile.is_open()) {
while (getline(infile, str)) {
char ch;
int i, j, len;
len = str.length();
for (i = 0; i < len; i++) {
for (j = 0; j < (len - 1); j++) {
if (str[j] > str[j + 1]) {
ch = str[j];
str[j] = str[j + 1];
str[j + 1] = ch;
}
}
}
cout << "\nProcessed data:" << str;
}
}
return 0;
}
For the input
Today is a fine day.
It's sunny.
Let us go out now!
this program has the following output:
0
Processed data: .Taaaddefiinosyy
Processed data: '.Innsstuy
Processed data: !Legnooosttuuw
Note that the input posted in your question contains a forward tick ’ instead of an apostrophe '. This could cause trouble. For example, when I tested your program, this forward tick was encoded into a multi-byte UTF-8 character, because it is not representable in 7-bit US-ASCII. This caused your sorting algorithm to fail, because it only supports single-byte characters. I was only able to fix this bug by replacing the forward tick with an apostrophe in the input.

File for loop doesn't open file c++

This file is not opening for a reason which I don't know really, any insight?
#include <iostream>
#include <string>
#include <algorithm>
#include <fstream>
#include <cctype>
using namespace std;
.
.
.
.
.
void MinHeap::TopKFrequentWord(string fileName, int k)
{
MinHeap mh;
Trie T;
string word;
string line;
ifstream inFile(fileName);
for (int i = 0; i < 22; i++)
{
if (i >= 10)
{
fileName = "C:\\Users\\Kareem's Laptop\\Desktop\\Reuters-21578\\reut2-0" + to_string(i) + ".sgm";
}
else if (i <= 9)
{
fileName = "C:\\Users\\Kareem's Laptop\\Desktop\\Reuters-21578\\reut2-00" + to_string(i) + ".sgm";
}
if (!inFile)
{
cout << fileName << " did not open." << endl;
exit(1);
}
bool found = true;
while (inFile >> line)
{
size_t pos = line.find("<BODY>");
if (pos != string::npos)
{
if (found)
{
word = line.substr(pos + 6);
found = true;
TrieNode* TN = T.search(word);
if (!TN)
{
TN = T.insert(word);
}
else
{
TN->frequency++;
}
mh.insert(TN, word);
}
}
}
mh.Display();
cout << '\n';
inFile.close();
}
}
int main()
{
MinHeap foo;
string fileName;
foo.TopKFrequentWord(fileName, 10);
return 0;
}
I have to open 21 files in a loop, read them all and print out the top 10 word count for all of those words.
Unable to use vector due to instructions. I apologize if similarities are obvious.
I tried putting all files in an array but it still didn't work. No errors just not opening (getting exit(1) command).
You are opening the file before the loop. Since you are updating the filename variable inside the loop, I suppose you want to open it each time you pass through the loop.
Move the line :
ifstream inFile(fileName);
to one line before the test:
if (!inFile)
Also, the place where you code ifstream inFile(fileName); you have an empty string in fileName (You didn't initialize the variable passed as argument in main).
Also, you are passing a int k parameter to the function but never uses it there.

Need to separate numbers from a string on a line, separated by ';', (25;16;67;13) in c++

We have a string (25;16;67;13;14;.......)
We need to print out the numbers separately. The last number does not have a semicolon behind it.
Output should be something like that:
25
16
67
13
14
......
Assuming we are using str.find, str.substr and size_t variables current_pos, prev_pos, what will be the condition of the while loop we are using to browse the line, so that it prints out all the numbers, not just the first one?
You can make use of std::istringstream:
#include <sstream>
#include <iostream>
int main() {
std::string text("25;16;67;13;14");
std::istringstream ss(text);
std::string token;
while(std::getline(ss, token, ';'))
{
std::cout << token << '\n';
}
return 0;
}
Running the above code online results in the following output:
25
16
67
13
14
If you need only to print the numbers in the string (rather than represent them in data structures) the solution is quite easy. Simply read the entire string, then print it character by character. If the character is a semicolon, print a new line instead.
#include <iostream>
#include <string>
using namespace std;
int main(){
string input;
cin >> input;
for(int i = 0; i < input.length(); i++){
if(input.at(i) == ';') cout << endl;
else cout << input.at(i);
}
}
using namespace std;
int main() {
string a{ "1232,12312;21414:231;23231;22" };
for (int i = 0; i < a.size(); i++) {
if (ispunct(a[i])) {
a[i] = ' ';
}
}
stringstream line(a);
string b;
while (getline(line, b, ' ')) {
cout << b << endl;
}
}
//any punctuation ",/;:<>="
I will give you an exact answer to your question with an example and an alternative solution with an one-liner.
Please see
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <regex>
const std::regex re(";");
int main() {
std::string test("25;16;67;13;14;15");
// Solution 1: as requested
{
size_t current_pos{};
size_t prev_pos{};
// Search for the next semicolon
while ((current_pos = test.find(';', prev_pos)) != std::string::npos) {
// Print the resulting value
std::cout << test.substr(prev_pos, current_pos - prev_pos) << "\n";
// Update search positions
prev_pos = current_pos + 1;
}
// Since there is no ; at the end, we print the last number manually
std::cout << test.substr(prev_pos) << "\n\n";
}
// Solution 2. All in one statement. Just to show to you what can be done with C++
{
std::copy(std::sregex_token_iterator(test.begin(), test.end(), re, -1), {}, std::ostream_iterator<std::string>(std::cout, "\n"));
}
return 0;
}

Trying to push an unknown number of strings into a vector, but my cin loop doesn't terminate

I am trying to take strings as input from cin, and then push the string into a vector each time. However, my loop doesn't terminate even when I put a '\' at the end of all my input.
int main(void) {
string row;
vector<string> log;
while (cin >> row) {
if (row == "\n") {
break;
}
log.push_back(row);
}
return 0;
}
I've tried replacing the (cin >> row) with (getline(cin,row)), but it didn't make any difference. I've tried using stringstream, but I don't really know how it works. How do I go about resolving this?
As commented by #SidS, the whitespace is discarded. So you have to think about another strategy.
You could instead check if row is empty. But that will only work with std::getline:
#include <vector>
#include <string>
#include <iostream>
int main() {
std::string row;
std::vector<std::string> log;
while (std::getline(std::cin, row)) {
if (row.empty()) {
break;
}
log.push_back(row);
}
std::cout << "done\n";
}
OP, in case you want to save single words (rather than a whole line), you can use regex to single-handedly push each of them into log after input:
#include <vector>
#include <string>
#include <iostream>
#include <regex>
int main() {
const std::regex words_reg{ "[^\\s]+" };
std::string row;
std::vector<std::string> log;
while (std::getline(std::cin, row)) {
if (row.empty()) {
break;
}
for (auto it = std::sregex_iterator(row.begin(), row.end(), words_reg); it != std::sregex_iterator(); ++it){
log.push_back((*it)[0]);
}
}
for (unsigned i = 0u; i < log.size(); ++i) {
std::cout << "log[" << i << "] = " << log[i] << '\n';
}
}
Example run:
hello you
a b c d e f g
18939823
#_#_# /////
log[0] = hello
log[1] = you
log[2] = a
log[3] = b
log[4] = c
log[5] = d
log[6] = e
log[7] = f
log[8] = g
log[9] = 18939823
log[10] = #_#_#
log[11] = /////
If you want to store the tokens of one line from std::cin, separated by the standard mechanism as in the operator>> overloads from <iostream> (i.e., split by whitespace/newline), you can do it like this:
std::string line;
std::getline(std::cin, line);
std::stringstream ss{line};
const std::vector<std::string> tokens{std::istream_iterator<std::string>{ss},
std::istream_iterator<std::string>{}};
Note that this is not the most efficient solution, but it should work as expected: process only one line and use an existing mechanism to split this line into individual std::string objects.
You can't read newline by using the istream& operator >> of string. This operator ignores whitespaces and will never return the string "\n". Consider using getline instead.

Outputting a map in a specific order

Hopefully I can explain exactly what's going on, but basically I have a map of words and their corresponding line numbers on a document that is read in by the program. I can output the map and everything with the words and their line numbers but I'm confused on how to change how they output. So here is the code:
here is the main:
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <fstream>
#include "dictionary.h"
#include "document.h"
using namespace std;
void sentancetoword(string sentance, set<string> words, int lineNum)
{
dictionary d;
document doc;
bool wordCheck;
string word;
stringstream ss(sentance);
while (ss >> word)
{
wordCheck = d.findWord(word, words);
if(!wordCheck)
{
doc.missingMap(word, lineNum);
}
}
doc.displayMap();
}
string letterCheck(string sentance)
{
for(unsigned i = 0; i < sentance.length(); i++)
{
if (!isalpha(sentance[i]))
{
sentance[i] = ' ';
}
}
return sentance;
}
int main(int argc, char* argv[])
{
dictionary dic;
document doc;
set<string> words;
set<string>::iterator it;
string doc_word;
int lineNum = 1;
ifstream in;
in.open(argv[1]);
string word;
while (in >> word)
{
transform(word.begin(), word.end(), word.begin(), ::tolower);
words.insert(word);
}
in.close();
//dic.makeSet(words);
ifstream in2;
in2.open(argv[2]);
while (getline(in2, doc_word))
{
transform(doc_word.begin(), doc_word.end(), doc_word.begin(), ::tolower);
doc_word = letterCheck(doc_word);
sentancetoword(doc_word, words, lineNum);
lineNum++;
}
in2.close();
system("pause");
return 0;
}
#include "document.h"
document::document(void){}
document::~document(void){}
void document::missingMap(string word, int lineNum)
{
misspelled[word].push_back(lineNum);
}
void document::displayMap()
{
for (map<string, vector<int>>::iterator i = misspelled.begin(); i != misspelled.end(); i++)
{
cout << i->first << ": ";
for (vector<int>::iterator j = i->second.begin(); j != i->second.end(); j++)
{
cout << *j << endl;
}
}
}
so the last function is doing the outputting of the map and it outputs as follows:
debugging: 1
process: 2
removing: 2
programming: 3
process: 4
putting: 4
but i need it to output like this:
debugging: 1
process: 2 4
programming: 3
putting: 4
removing: 2
is there something I'm doing wrong in the code or do i need to add a sort function to sort it by the words? I'm honestly lost and don't know where to go from here to get it to output only the word one time followed by the line numbers it appears on. If anyone could help that would be great, and if any more information is needed I'll be happy to add it to the question! Thanks!
Your output doesn't make sense, though I think you will want to do this:
cout << i->first << ": ";
for (vector<int>::iterator j = i->second.begin(); j != i->second.end(); j++)
{
cout << *j << " ";
}
cout << "\n"; //endl is okay, but I prefer only for I really do need to flush the stream