Lets say I have a code :
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string line,wantedString,newString;
fstream subor("test.txt");
while (!subor.fail()) // read line from test.txt
{
getline(subor,line);
line.substr(line.find("?")+1);
wantedString=line.substr(line.find("?")+1); // will take everything after '?' character till
'\n'
}
cout<<"Enter new text to replace wantedString :";
getline(cin,newString);
// how to use string::replace() please ?
/I tried this but does not work
getline(subor,line);
line.replace(wantedString,string::npos,newString);
return 0;
}
In test.txt is written only one line :
something?replace
note: there is no '\n' in the file
error thrown by compiler is :
error: no matching function for call to 'std::__cxx11::basic_string<char>::replace(std::__cxx11::string&, const size_type&, std::__cxx11::string&)'
can you please answer working code with commented explaining why is it like you did it ?
I have studied string::replace() method here:
http://www.cplusplus.com/reference/string/string/replace/
Is my logic of using string::find() as a starting point for string to be replaced ?
Is my logic of using string::find() as a starting point for string to be replaced ?
Yes, but then you threw away the iterator/index result of find and went to get the substring instead.
Replace doesn't take a string.
It takes an iterator/index.
So just pass what you got from find, into replace. (Be careful of edge cases! Check for errors! Read the documentation for both functions.)
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
fstream subor("test.txt");
string line;
while (getline(subor,line))
{
// Find the index of the character after the first '?'
const size_t wantedStringPos = line.find("?")+1;
// Prompt for a replacement string
cout << "Enter new text to replace wantedString: ";
string newString;
getline(cin,newString);
// Perform the replacement
line.replace(wantedStringPos, string::npos, newString);
// Now do something with `line`
// [TODO]
}
}
(I've also fixed an off-by-one error in your loop.)
You then need to actually write the new, modified string back to the file: the file doesn't automatically get updated in sync with the copy of the data you previously read out from it.
Related
Trying to use getline but the error keeps saying:
No instance of overloaded function matches argument list.
#include <iomanip>
#include <string>
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main()
{
int lengthInput;
int widthInput;
ifstream fileOpening;
fileOpening.open("testFile.txt");
while (!fileOpening.eof())
{
//ERROR ON NEXT TWO LINES OF CODE**
getline(fileOpening, lengthInput, ' ');
getline(fileOpening, widthInput, ' ');
}
system("pause");
return 0;
The 2nd parameter of std::getline() expects a std::string to write to, but in both cases you are passing in an int instead. That is why you are getting the error - there really is no version of std::getline() that matches your code.
The second argument of getline is expected to be a reference to a std::string, not a reference to an int.
If you expect that the pair of values can be read from multiple lines, you can use:
while (fileOpening >> lengthInput >> widthInput)
{
// Got the input. Use them.
}
If you expect that the pair of values must be read from each line, you'll have to use a different strategy.
Read lines of text.
Process each line.
std::string line;
while ( fileOpening >> line )
{
std::istringstream str(line);
if (str >> lengthInput >> widthInput)
{
// Got the input. Use them.
}
}
Important Note
Don't use
while (!fileOpening.eof()) { ... }
See Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?.
i was hoping to get some feedback on if i am doing this the "smart way" or if maybe i could be doing it faster. if i were splitting on white spaces
i would probably use getline(stringstream, word, delimiter)
but i didnt know how to adapt the delimiter to all the good characters so i just looped through the whole string generated a new word until i reached a bad character but as i am fairly new to programming im not sure if its the best way to do it
thanks for any feedback
#include <iostream>
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <sstream>
#include <algorithm>
#include <iterator> //delete l8r
using std::cout; using std::cin; using std::endl;
/*
void split(string line, vector<string>&words, string good_chars)
o
Find words in the line that consist of good_chars.
Any other character is considered a separator.
o
Once you have a word, convert all the characters to lower case.
You then push each word onto the reference vector words.
Important: split goes in its own file. This is both for your own benefit, you can reuse
split, and for grading purposes.We will provide a split.h for you.
*/
void split(string line, vector<string> & words, string good_chars){
string good_word;
for(auto c : line){
if(good_chars.find(c)!=string::npos){
good_word.push_back(c);
}
else{
if(good_word.size()){
std::transform(good_word.begin(), good_word.end(), good_word.begin(), ::tolower);
words.push_back(good_word);
}
good_word = "";
}
}
}
int main(){
vector<string> words;
string good_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'";
// TEST split
split("This isn't a TEST.", words, good_chars);
// words should have: {"this", "isn't", "a", "test"}, no period in test
std::copy(words.begin(), words.end(), std::ostream_iterator<string>(cout, ","));
cout << endl;
return 0;
}
I'd say that this is a reasonable approach given the context of an intro to C++ class. I'd even say that it's fairly likely that this is the approach your instructor expects to see.
There are, of course, a few optimization tweaks that can be done. Like instantiating a 256-element bool array, using good_chars to set the corresponding values to true, and all others defaulting to false, then replacing the find() call with a quick array lookup.
But, I'd predirect that if you were to hand in such a thing, you'll be suspected of copying stuff you found on the intertubes, so leave that alone.
One thing you might consider doing is using tolower when you push_back each character, instead, and removing the extra std::transform pass over the word.
I've spent a lot of time looking online to find a answer for this, but nothing was helping, so I figured I'd post my specific scenario. I have a .txt file (see below), and I am trying to write a routine that just finds a certain chunk of a certain line (e.g. I want to get the 5 digit number from the second column of the first line). The file opens fine and I'm able to read in the entire thing, but I just don't know how to get certain chunks from a line specifically. Any suggestions? (NOTE: These names and numbers are fictional...)
//main cpp file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ifstream fin;
fin.open("customers.txt");
return 0;
}
//customers.txt
100007 13153 09067.50 George F. Thompson
579489 21895 00565.48 Keith Y. Graham
711366 93468 04602.64 Isabel F. Anderson
Text parsing is not such a trivial thing to implement.
If your format won't change you could try to parse it by yourself, use random access file access and use regular expressions to extract the part of the stream that you need, or read a certain quantity of chars.
If you go the regex way, you'll need C++11 or a third party library, like Boost or POCO.
If you can format the text file then you might also want to choose a standard to structure your data, like XML, and use the facilities of that format to extract the information you want. POCO might help you there.
Some simple hints in your code to help you, you will need to complete the code. But the missing pieces are easy to find at stackoverflow.
//main cpp file
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
splitLine(const char* str, vector<string> results){
// splits str and stores each value in results vector
}
int main()
{
ifstream fin;
fin.open("customers.txt");
char buffer[128];
if(fin.good()){
while(!fin.eof()){
fin.getline(buffer, 256);
cout << buffer << endl;
vector<string> results;
splitLine(buffer, results);
// now results MUST contain 4 strings, for each
// column in a line
}
}
return 0;
}
If the columns are separated by whitespace then the second column of the first row is simpy the second token extracted from the stream.
std::ifstream input{"customers.txt"}; // Open file input stream.
std::istream_iterator<int> it{input}; // Create iterator to first token.
int number = *std::next(it); // Advance to next token and dereference.
Here's my attempt at it:
#include <iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world!..!.");
for (auto &c : s)
if(!ispunct(c))
{
cout<<s;
}
}
Here's the output
hello world!..!.hello world!..!.hello world!..!.hello world!..!.hello world!..!.
hello world!..!.hello world!..!.hello world!..!.hello world!..!.hello world!..!.
hello world!..!.
Here's another attempt:
#include <iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world!..!.");
for (auto &c : s)
if(!ispunct(c))
{
cout<<c;
}
}
This gives the correct output (i.e : hello world)
Why won't cout<<s; give me the correct output? After all c is a reference, so any changes to c would also apply to s. Or am I wrong about this?
This is why i don't really like the auto feature, auto in your case is a char and there is no elimination from the string.
LE: ispunct doesn't remove the character from the string, it doesn't even know (or care) that you have a string, it only returns true if the character is punctuation character or false if not, and based on that return the cout statement is executed with the character that is not punctuation or not executed for punctuation character.
s is the entire string, so cout<<s sends the entire string to your output stream :\
Your second attempt works because you're sending individual characters to the stream. In the first attempt though, you're sending the whole string for each character that exists in the string. Count the number of non-punct characters in your string, then count the number of times the string was printed out ;)
ispunct does not eliminate the character that is a punct. It only returns 0 or non-zero to indicate
if it is punct or no.
When you encounter a character that is not punct, it returns 0. And you enter your if. You are printing s that is the whole string.
Whereas, with cout<<c you only print the character (which is non punct, since you are now in the loop)
One more variant, using STL algorithms:
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
using std::cout;
using std::endl;
using std::string;
using std::back_inserter;
using std::copy_if;
int main()
{
string s("hello world!..!.");
string result = "";
copy_if(begin(s), end(s),
back_inserter(result),
[](char c){return !ispunct(c);}
);
cout << result << endl;
}
For real world code it's recommended to prefer suitable STL algorithms if available over a loop, because saying copy_if states your intent clearly, and does not focus on the individual steps to take. Whether or not it's better in this example I don't want to judge. But it's certainly good to keep this possibility in mind!
One more thing: It's generally regarded a bad thing to write using namespace std, because this can lead to name collisions when a future version of C++ introduces new keywords which you've already defined yourself in your own code. Either use the prefix std:: all the time, or follow the way I've shown in my example, this keeps your code safe.
EDIT - there are no blank lines.
EDIT 2 - my bad, it seems I was wrong all along. There is a blank line somewhere, although the csv file indicates otherwise. It's working now.
Okay so here is the entire (short) program:
#include <iostream>
#include <cctype>
#include <string>
#include <fstream>
using namespace std;
int main(){
char a;
string stringmanip;
fstream myfile("readthisfile.csv");
if (myfile.is_open()){
while ( myfile.good() ){
getline(myfile,stringmanip);
a=stringmanip[0];
}
myfile.close();
}
else cout<< "Unable to open file";
return 0;
}
It makes no sense to me. I can copy stringmanip, I can cout stringmanip, I can use .substr with stringmanip. If I define a regular string I can use the [] operation just fine. I've tried .at as well, but that only leads to another error. (Out of range).
Any help would be GREATLY appreciated. Sorry I'm such a beginner, as I'm sure you can tell.
Thanks,
Ben
If readthisfile.csv has an empty line at the end of the file (or anywhere in the file), then you will get back an empty string. You can't dereference the 0th character of an empty string. string::operator[] only accepts indices from 0 to string::length() - 1. If you have an empty string, any call to string::operator[] will result in undefined behavior.