I'm struggling to find a way to decrease the value in a string every time the string is shown.
Using the code below, consider that the 1st line of the text file is some text #N. #N should be replaced by a number decreasing from 18 to 1. When it reaches 0 it should go back to 18.
#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
void find_and_replace(string & source, string const & find, string const & replace)
{
for (string::size_type i = 0; (i = source.find(find, i)) != string::npos;) {
source.replace(i, find.length(), replace);
i += replace.length();
}
}
int main(int argc, char * argv[])
{
std::ifstream fileIn("Answers.txt", std::ios::in | std::ios::binary);
string question;
string line;
if (!fileIn) {
cout << "Cannot open input file!" << endl;
return 1;
}
while (getline(fileIn, line)) {
if (line == "The answer can be found in a secret place in the woods.") {
fileIn.clear();
fileIn.seekg(0, ios::beg);
}
cout << "Ask a question followed by the Enter key. Or type 'exit' to Exit program.\n";
getline(cin, question);
system("CLS");
find_and_replace(line, "#N", "18");
if (question == "") {
cout << "Your input cannot be blank. Please try again.\n\n";
}
else if (question == "exit")
exit(0);
else {
cout << "Q: " + question
<< "\nA: " + line + "\n\n";
}
}
}
This code only changes #N to 18, nothing more.
Please help guys.
You have hardcoded the value to 18, and you don't have any code which decrements the number.
Try these changes
put this at the start of main
int tempVar=18;
char buffer[100];
and replace
find_and_replace(line, "#N", "18");
with
sprintf(buffer,"%d",tempVar--)
if(tempVar<0)
tempVar=18;
find_and_replace(line, "#N", buffer);
https://www.programiz.com/cpp-programming/library-function/cstdio/sprintf
You can use something like:
#include <sstream>
#include <string>
class Replacer
{
const std::string token_;
const int start_;
int current_;
public:
explicit Replacer(const std::string & token, int start)
: token_(token), start_(start), current_(start)
{
}
std::string replace(const std::string & str)
{
const std::size_t pos = str.find(token_);
if (pos == std::string::npos)
return str;
std::string ret(str);
std::ostringstream oss;
oss << current_;
ret.replace(pos, token_.size(), oss.str());
--current_;
if (current_ == 0)
current_ = start_;
return ret;
}
};
And then you can use it like:
std::string examples[] = {
"",
"nothing",
"some number #N",
"nothing",
"some other #N number",
"nothing",
"#N another test",
"nothing",
};
Replacer replacer("#N", 18);
for (int i = 0; i < 8; ++i)
std::cout << replacer.replace(examples[i]) << '\n';
Related
Basically, I have to show each word with their count but repeated words show up again in my program.
How do I remove them by using loops or should I use 2d arrays to store both the word and count?
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <conio.h>
#include <time.h>
using namespace std;
char* getstring();
void xyz(char*);
void tokenizing(char*);
int main()
{
char* pa = getstring();
xyz(pa);
tokenizing(pa);
_getch();
}
char* getstring()
{
static char pa[100];
cout << "Enter a paragraph: " << endl;
cin.getline(pa, 1000, '#');
return pa;
}
void xyz(char* pa)
{
cout << pa << endl;
}
void tokenizing(char* pa)
{
char sepa[] = " ,.\n\t";
char* token;
char* nexttoken;
int size = strlen(pa);
token = strtok_s(pa, sepa, &nexttoken);
while (token != NULL) {
int wordcount = 0;
if (token != NULL) {
int sizex = strlen(token);
//char** fin;
int j;
for (int i = 0; i <= size; i++) {
for (j = 0; j < sizex; j++) {
if (pa[i + j] != token[j]) {
break;
}
}
if (j == sizex) {
wordcount++;
}
}
//for (int w = 0; w < size; w++)
//fin[w] = token;
//cout << fin[w];
cout << token;
cout << " " << wordcount << "\n";
}
token = strtok_s(NULL, sepa, &nexttoken);
}
}
This is the output I get:
I want to show, for example, the word "i" once with its count of 5, and then not show it again.
First of all, since you are using c++, I would recommend you to split text in c++ way(some examples are here), and store every word in map or unordered_map. Example of my realization you can find here
But if you don't want to rewrite your code, you can simply add a variable that will indicate whether a copy of the word was found before or after the word position. If a copy was not found in front, then print your word
This post gives an example to save each word from your 'strtok' function into a vector of string. Then, use string.compare to have each word compared with word[0]. Those indexes match with word[0] are marked in an int array 'used'. The count of match equals to the number marks in the array used ('nused'). Those words of marked are then removed from the vector, and the remaining carries on to the next comparing process. The program ends when no word remained.
You may write a word comparing function to replace 'str.compare(str2)', if you prefer not to use std::vector and std::string.
#include <iostream>
#include <string>
#include <vector>
#include<iomanip>
#include<cstring>
using namespace std;
char* getstring();
void xyz(char*);
void tokenizing(char*);
int main()
{
char* pa = getstring();
xyz(pa);
tokenizing(pa);
}
char* getstring()
{
static char pa[100] = "this is a test and is a test and is test.";
return pa;
}
void xyz(char* pa)
{
cout << pa << endl;
}
void tokenizing(char* pa)
{
char sepa[] = " ,.\n\t";
char* token;
char* nexttoken;
std::vector<std::string> word;
int used[64];
std::string tok;
int nword = 0, nsize, nused;
int size = strlen(pa);
token = strtok_s(pa, sepa, &nexttoken);
while (token)
{
word.push_back(token);
++nword;
token = strtok_s(NULL, sepa, &nexttoken);
}
for (int i = 0; i<nword; i++) std::cout << word[i] << std::endl;
std::cout << "total " << nword << " words.\n" << std::endl;
nsize = nword;
while (nsize > 0)
{
nused = 0;
tok = word[0] ;
used[nused++] = 0;
for (int i=1; i<nsize; i++)
{
if ( tok.compare(word[i]) == 0 )
{
used[nused++] = i; }
}
std::cout << tok << " : " << nused << std::endl;
for (int i=nused-1; i>=0; --i)
{
for (int j=used[i]; j<(nsize+i-nused); j++) word[j] = word[j+1];
}
nsize -= nused;
}
}
Notice that the removal of used words has to do in backward order. If you do it in sequential order, the marked indexes in the 'used' array will need to be changed. A running test:
$ ./a.out
this is a test and is a test and is test.
this
is
a
test
and
is
a
test
and
is
test
total 11 words.
this : 1
is : 3
a : 2
test : 3
and : 2
I read your last comment.
But I am very sorry, I do not know C. So, I will answer in C++.
But anyway, I will answer with the C++ standard approach. That is usually only 10 lines of code . . .
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <regex>
// Regex Helpers
// Regex to find a word
static const std::regex reWord{ R"(\w+)" };
// Result of search for one word in the string
static std::smatch smWord;
int main() {
std::cout << "\nPlease enter text: \n";
if (std::string line; std::getline(std::cin, line)) {
// Words and its appearance count
std::map<std::string, int> words{};
// Count the words
for (std::string s{ line }; std::regex_search(s, smWord, reWord); s = smWord.suffix())
words[smWord[0]]++;
// Show result
for (const auto& [word, count] : words) std::cout << word << "\t\t--> " << count << '\n';
}
return 0;
}
Hi I need to find second to last word in a string. Right now below program is printing the last one.
#include <iostream>
#include <string>
using namespace std;
int main() {
string text{"some line with text"};
// find last space, counting from backwards
int i = text.length() - 2; // last character
while (i != 0 && !isspace(text[i]))
{
--i;
}
string lastword = text.substr(i+1); // +1 to skip leading space
cout << lastword << endl;
return 0;
}
Output: (Printing last word)
text
You can split the string into words and hold the previous word before saving the current word.
#include <iostream>
#include <string>
#include <sstream>
int main() {
std::string text{"some line with text"};
std::stringstream ss(text);
std::string previousword, lastword, newword;
while (ss >> newword) {
previousword = lastword;
lastword = newword;
}
std::cout << previousword << std::endl;
return 0;
}
Also note that using using namespace std; is discouraged.
You don't need any loops. Just add error checking:
int main() {
std::string text{ "some line with text" };
std::size_t pos2 = text.rfind(' ');
std::size_t pos1 = text.rfind(' ', pos2-1);
std::cout << text.substr(pos1+1, pos2-pos1-1) << std::endl;
return 0;
}
Just keep counting spaces until you arrive to the word you want or use a stringstream as MikeCAT proposed.
Here there is a function that finds any last word number without having to copy the entire string in a stringstream:
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
string getNLastWord(string text, int n)
{
bool insideAWord = false;
int wordNum = 0;
int wordEnd = -1;
for(int i = text.size() - 1; i > 0; i--)
{
if(text[i] != ' ' && !insideAWord)
{
wordNum++;
insideAWord = true;
}
else if(text[i] == ' ')
{
insideAWord = false;
}
if(wordNum == n)
{
wordEnd = i;
break;
}
}
if(wordEnd == -1)
{
cout << "There are no " << n << " words from right." << endl;
}
else
{
int wordStart;
for(wordStart = wordEnd; wordStart > 0; wordStart--)
{
if(text[wordStart] == ' ')
{
wordStart++;
break;
}
}
return text.substr(wordStart,wordEnd+1-wordStart);
}
return "";
}
int main() {
string text = "some text";
cout << getNLastWord(text,2);
return 0;
}
In my project, I need to sort out a list in a file.txt file contains different words. I need my program to recognize this 3 names : bob, alicia and cookie. And each time when he found for exemple "cookie" I want to display "dog" as a result, for "alicia" "girl" and for "bob" "boy" and for an other word "unknown".
The text file contains :
hello
shirley
cookie
bob
alicia
cook
road
alicia
stole
bob
So I did this type of code :
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream input;
size_t pos;
string line;
input.open("file.txt");
if(input.is_open())
{
while(getline(input,line))
{
pos = line.find("cookie");
pos = line.find("bob");
pos = line.find("alicia");
if(pos!=string::npos) // string::npos is returned if string is not found
{
cout <<"dog \n";
cout <<"girl \n";
cout <<"boy \n";
break;
}
}
}
}
And when this code take file.txt like an entry I didn't have the right result like this :
unknown
unknown
dog
boy
girl
unknown
unknown
girl
unknown
boy
Can you help me please because I don't know can I have this result?
Few problems here
You are rewriting the pos in the while loop.
You only print dog girl and boy at once if you find alicia in the file(pos overwriting issue).
You are not handling the case for unknown.
Hence replace your
while(getline(input,line))
{
pos = line.find("cookie");
pos = line.find("bob");
pos = line.find("alicia");
if(pos!=string::npos) // string::npos is returned if string is not found
{
cout <<"dog \n";
cout <<"girl \n";
cout <<"boy \n";
break;
}
}
with
while(getline(input,line))
{
if ((line.find("bob")) != string::npos)
{
cout <<"boy \n";
}
else if ((line.find("alicia")) != string::npos)
{
cout <<"girl \n";
}
else if ((line.find("cookie")) != string::npos)
{
cout <<"dog\n";
}
else
{
cout <<"unknown \n";
}
}
Output:
unknown
unknown
dog
boy
girl
unknown
unknown
girl
unknown
boy
Note :: This approach finds the one word(including substring) in each line.
Using the stream extracion operator >> would have been easier:
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
int main()
{
char const *filename{ "file.txt" };
std::ifstream is{ filename };
if (!is.is_open()) {
std::cerr << "Couldn't open \"" << filename << "\" for reading!\n\n";
return EXIT_FAILURE;
}
std::string word;
while (is >> word) {
if (word == "cookie")
std::cout << "dog\n";
else if (word == "bob")
std::cout << "boy\n";
else if (word == "alicia")
std::cout << "girl\n";
else
std::cout << "unknown\n";
}
}
If it would be required that only the first word of a line be considered a name one could write a manipulator that eats everything until a newline or EOF is encountered:
std::istream& eat_till_newline(std::istream& is)
{
int ch;
while ((ch = is.get()) != EOF && ch != '\n');
return is;
}
usage:
while (is >> word >> eat_till_newline)
To further narrow down what a word is, one could remove all non-letters from the right of the string:
#include <string>
#include <cctype>
// ...
std::string r_trim(std::string str, int(*pred)(int))
{
std::size_t i = str.length();
if (!i)
return str;
for(; i > 0 && !pred(static_cast<int>(str[i-1])); --i);
return str.substr(0, i);
}
usage:
while (is >> word >> eat_till_newline) {
word = trim_r(word, std::isalpha);
if (word == "cookie")
std::cout << "dog\n";
else if (word == "bob")
std::cout << "boy\n";
else if (word == "alicia")
std::cout << "girl\n";
else
std::cout << "unknown\n";
}
To put it all together:
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
std::istream& eat_till_newline(std::istream& is)
{
int ch;
while ((ch = is.get()) != EOF && ch != '\n');
return is;
}
std::string r_trim(std::string str, int(*pred)(int))
{
std::size_t i = str.length();
if (!i)
return str;
for(; i > 0 && !std::isalpha(static_cast<int>(str[i-1])); --i);
return str.substr(0, i);
}
int main()
{
char const *filename{ "test.txt" };
std::ifstream is{ filename };
if (!is.is_open()) {
std::cerr << "Couldn't open \"" << filename << "\" for reading!\n\n";
return EXIT_FAILURE;
}
std::string word;
while (is >> word >> eat_till_newline) {
word = r_trim(word, std::isalpha);
if (word == "cookie")
std::cout << "dog\n";
else if (word == "bob")
std::cout << "boy\n";
else if (word == "alicia")
std::cout << "girl\n";
else
std::cout << "unknown\n";
}
}
Here is the codeshare link of the exact input file: https://codeshare.io/5DBkgY
Ok, as you can see, there are 2 blank lines, (or tabs) between 8 and ROD. How would I skip that and continue with the program? I am trying to put each line into 3 vectors (so keys, lamp, and rod into one vector etc). Here is my code (but it does not skip the blank line).:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>
using namespace std;
int main() {
ifstream objFile;
string inputName;
string outputName;
string header;
cout << "Enter image file name: ";
cin >> inputName;
objFile.open(inputName);
string name;
vector<string> name2;
string description;
vector<string> description2;
string initialLocation;
vector<string> initialLocation2;
string line;
if(objFile) {
while(!objFile.eof()){
getline(objFile, line);
name = line;
name2.push_back(name);
getline(objFile, line);
description = line;
description2.push_back(description);
getline(objFile, line);
initialLocation = line;
initialLocation2.push_back(initialLocation);
} else {
cout << "not working" << endl;
}
for (std::vector<string>::const_iterator i = name2.begin(); i != name2.end(); ++i)
std::cout << *i << ' ';
for (std::vector<string>::const_iterator i = description2.begin(); i != description2.end(); ++i)
std::cout << *i << ' ';
for (std::vector<string>::const_iterator i = initialLocation2.begin(); i != initialLocation2.end(); ++i)
std::cout << *i << ' ';
#include <cstddef> // std::size_t
#include <cctype> // std::isspace()
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
bool is_empty(std::string const &str)
{
for (auto const &ch : str)
if (!std::isspace(static_cast<char unsigned>(ch)))
return false;
return true;
}
int main()
{
std::cout << "Enter image file name: ";
std::string filename;
std::getline(std::cin, filename); // at least on Windows paths containing whitespace
// are valid.
std::ifstream obj_file{ filename }; // define variables as close to where they're used
// as possible and use the ctors for initialization.
if (!obj_file.is_open()) { // *)
std::cerr << "Couldn't open \"" << filename << "\" for reading :(\n\n";
return EXIT_FAILURE;
}
std::vector<std::string> name;
std::vector<std::string> description;
std::vector<std::string> initial_location;
std::string line;
std::vector<std::string> *destinations[] = { &name, &description, &initial_location };
for (std::size_t i{}; std::getline(obj_file, line); ++i) {
if (is_empty(line)) { // if line only consists of whitespace
--i;
continue; // skip it.
}
destinations[i % std::size(destinations)]->push_back(line);
}
for (auto const &s : name)
std::cout << s << '\n';
for (auto const &s : description)
std::cout << s << '\n';
for (auto const &s : initial_location)
std::cout << s << '\n';
}
... initial_locations look like integers, though.
*) Better early exit if something bad happens. Instead of
if (obj_file) {
// do stuff
}
else {
// exit
}
-->
if(!obj_file)
// exit
// do stuff
makes your code easier to read and takes away one level of indentation for the most parts.
I'm a beginner in c++ and required to write a c++ program to read and print a csv file like this.
DateTime,value1,value2
12/07/16 13:00,3.60,50000
14/07/16 20:00,4.55,3000
May I know how can I proceed with the programming?
I manage to get the date only via a simple multimap code.
I spent some time to make almost (read notice at the end) exact solution for you.
I assume that your program is a console application that receives the original csv-file name as a command line argument.
So see the following code and make required changes if you like:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
std::vector<std::string> getLineFromCSV(std::istream& str, std::map<int, int>& widthMap)
{
std::vector<std::string> result;
std::string line;
std::getline(str, line);
std::stringstream lineStream(line);
std::string cell;
int cellCnt = 0;
while (std::getline(lineStream, cell, ','))
{
result.push_back(cell);
int width = cell.length();
if (width > widthMap[cellCnt])
widthMap[cellCnt] = width;
cellCnt++;
}
return result;
}
int main(int argc, char * argv[])
{
std::vector<std::vector<std::string>> result; // table with data
std::map<int, int> columnWidths; // map to store maximum length (value) of a string in the column (key)
std::ifstream inpfile;
// check file name in the argv[1]
if (argc > 1)
{
inpfile.open(argv[1]);
if (!inpfile.is_open())
{
std::cout << "File " << argv[1] << " cannot be read!" << std::endl;
return 1;
}
}
else
{
std::cout << "Run progran as: " << argv[0] << " input_file.csv" << std::endl;
return 2;
}
// read from file stream line by line
while (inpfile.good())
{
result.push_back(getLineFromCSV(inpfile, columnWidths));
}
// close the file
inpfile.close();
// output the results
std::cout << "Content of the file:" << std::endl;
for (std::vector<std::vector<std::string>>::iterator i = result.begin(); i != result.end(); i++)
{
int rawLen = i->size();
for (int j = 0; j < rawLen; j++)
{
std::cout.width(columnWidths[j]);
std::cout << (*i)[j] << " | ";
}
std::cout << std::endl;
}
return 0;
}
NOTE: Your task is just to replace a vector of vectors (type std::vector<std::vector<std::string>> that are used for result) to a multimap (I hope you understand what should be a key in your solution)
Of course, there are lots of possible solutions for that task (if you open this question and look through the answers you will understand this).
First of all, I propose to consider the following example and to try make your task in the simplest way:
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string str = "12/07/16 13:00,3.60,50000";
stringstream ss(str);
vector<string> singleRow;
char ch;
string s = "";
while (ss >> ch)
{
s += ch;
if (ss.peek() == ',' || ss.peek() == EOF )
{
ss.ignore();
singleRow.push_back(s);
s.clear();
}
}
for (vector<string>::iterator i = singleRow.begin(); i != singleRow.end(); i++)
cout << *i << endl;
return 0;
}
I think it can be useful for you.