C++ introduction: self study - c++

I created the program to read from text file and remove special characters. I can't seem to code better the if statement. Please help. I searched online for the right code statements but they have all advanced code statements. The book I am learning from has the last(14th) chapter with strings and file open and closing code. I tried creating an array of special chars, but did not work. Please help me!
int main()
{
string paragraph = "";
string curChar = "";
string fileName = "";
int subscript=0;
int numWords=0;
ifstream inFile; //declaring the file variables in the implement
ofstream outFile;
cout << "Please enter the input file name(C:\owner\Desktop\para.txt): " << endl;
cin >> fileName;
inFile.open(fileName, ios::in); //opening the user entered file
//if statement for not finding the file
if(inFile.fail())
{
cout<<"error opening the file.";
}
else
{
getline(inFile,paragraph);
cout<<paragraph<<endl<<endl;
}
numWords=paragraph.length();
while (subscript < numWords)
{
curChar = paragraph.substr(subscript, 1);
if(curChar==","||curChar=="."||curChar==")"
||curChar=="("||curChar==";"||curChar==":"||curChar=="-"
||curChar=="\""||curChar=="&"||curChar=="?"||
curChar=="%"||curChar=="$"||curChar=="!"||curChar==" ["||curChar=="]"||
curChar=="{"||curChar=="}"||curChar=="_"||curChar==" <"||curChar==">"
||curChar=="/"||curChar=="#"||curChar=="*"||curChar=="_"||curChar=="+"
||curChar=="=")
{
paragraph.erase(subscript, 1);
numWords-=1;
}
else
subscript+=1;
}
cout<<paragraph<<endl;
inFile.close();

You might want to look into the strchr function which searches a string for a given character:
include <string.h>
char *strchr (const char *s, int c);
The strchr function locates the first occurrence of c (converted to a char) in the
string pointed to by s. The terminating null character is considered to be part of the
string.
The strchr function returns a pointer to the located character, or a null pointer if the
character does not occur in the string.
Something like:
if (strchr (",.();:-\"&?%$![]{}_<>/#*_+=", curChar) != NULL) ...
You'll have to declare curChar as a char rather than a string and use:
curChar = paragraph[subscript];
rather than:
curChar = paragraph.substr(subscript, 1);
but they're relatively minor changes and, since your stated goal was I want to change the if statement into [something] more meaningful and simple, I think you'll find that's a very good way to achieve it.

In <cctype> header we have functions like isalnum(c) which returns true iff c is an alpanumeric character, isdigit(c) etc... I think the condition you are looking for is
if(isgraph(c) && !isalnum(c))
But c must be a char, not an std::string (well, technically speaking c must be int, but the conversion is implicit:) hth
P.S. This isn't the best idea, but if you want to keep sticking with std::string for curChar, c will be this char c = curChar[0]

since you are learning c++, I will introduce you the c++ iterator way of erasing.
for (string::iterator it = paragraph.begin();
it != paragraph.end();
++it)
while (it != paragraph.end() && (*it == ',' || *it == '.' || ....... ))
it = paragraph.erase(it);
First, try using iterator. This won't give you best performance, but its concept would help you work with other c++ structure.
if(curChar==","||curChar=="."||curChar==")" ......
Second, single quote ' and double quote " differs. You use ' for char.

Related

Replace all occurrences of one string with another in a stream of text

As the title says, how do I replace a string with another string? For example: the user would enter three inputs. The first input is the string that the program would replace; the second is the string that would replace input1; and the third is the string that would be printed out. So if:
Input1 = peanut
Input2 = coconut
Input3 = replacepeanutreplace
Output: replacecoconutreplace
I have started it but my program can only replace words with the same length. I tried searching my problem, but I do not understand the given solutions since I am just new at C/C++.
char replacing[100];
char replacement[100];
char original[1000];
int count;
cin >> replacing;
cin >> replacement;
while(! cin.eof())
{
cin >> original;
char * pch;
pch = strstr (original, replacing);
count = strlen(replacement);
strncpy (pch, replacement, count);
cout << original << endl;
}
What about:
You first find (if any) an occurrence of that string
Use replace to substitute the occurrence with the second string
Here is something that should work:
bool replaceFirst(string& input, const std::string& toBeReplaced, const std::string& replacement) {
size_t start_pos = input.find(toBeReplaced);
if(start_pos == std::string::npos)
return false; //substring not found!
input.replace(start_pos, toBeReplaced.length(), replacement); //found. now i can replace!
return true;
}
Since you are using an array of char instead of string you have to make sure that replacing does not lead you out of bound (strings auto-resize for you).
The key problem is that strncpy does not allocate (or free) any memory. This means that if replacement is shorter that replacing, part of replacing will not be overwritten. Similarly if replacement is longer it will overwrite beyond the end of replacing.
As already said, you would be better off using std::string (or some other C++ string class like Qt's QString if Qt is your cup of tea).
One other little thing, in general with streams it's best not to just check for eof, rather write something like
while (cin >> original) {
This will terminate if the stream is in any fail state, not just eof.

Reverse word in a string

This code here is for reversing words in a string. The problem is that it only reverses the first word in the string. When I ran a trace I found that it is stopping after encountering the statement if(s[indexCount] == '\0') break;
Why the code is getting null character every time the first word is reversed even though some other character is present after the first word.
#include <iostream>
using namespace std;
int main()
{
string s;
char tchar;
int indexCount=0,charCount=0,wordIndex;
cin>>s;
while(1){
if(s[indexCount]==' ' && charCount==0) continue;
if(s[indexCount]==' ' || s[indexCount]=='\0' ){
wordIndex=indexCount-charCount;
charCount=indexCount-1;
while(charCount!=wordIndex && charCount>wordIndex){
tchar=s[wordIndex];
s[wordIndex]=s[charCount];
s[charCount]=tchar;
charCount--;
wordIndex++;
}
if(s[indexCount] == '\0') break;
indexCount++; charCount=0;
}
else{
charCount++;
indexCount++;
}
}
cout<<"\nReveresed words in the string : \n\t"<<s<<endl;
return 0;
}
Also I'm using while(1). Does it make this a bad code?
The problem indeed lies with the method of input. cin >> string_variable will consider whitespace to be a delimiter. That is why only the first word is being entered. Replace cin >> s; with getline(cin, s); and it will work correctly.
First of all I want to point out that
cin >> stringObject;
will never ever read space character! so inserting My name is geeksoul will cause above code to read only My and leave everything else in the buffer!
To read space character you should use getline function like this
std::getline(std::cin, stringObject);
read about getline
Second The standard doesn't say that in case of an std::string '\0' is any special character. Therefore, any compliant implementation of std::string should not treat '\0' as any special character. Unless of course a const char* is passed to a member function of a string, which is assumed to be null-terminated.
If you really want to check your string with null terminating character then you should consider using stringObject.c_str() which converts your C++ style string to old school C style string!
Check this for c_str
Finally this might be helpful for you!
Quick tip.
If you reverse all characters in the whole strings, and then all characters between each pair of consecutive spaces, you will achieve the same result, with way simple code, like this: (Note, this may not compile or be slightly buggy (haven't compiled or anything), but should convey the basic idea)
void reverseWords(std::string& aString) {
std::reverse(aString.begin(), aString.end());
size_t lastSpaceIndex = 0;
for (size_t index = 0; index != aString.size(); ++index) {
if (aString[index] == ' ') {
std::reverse(aString.begin() + lastSpaceIndex + 1, aString.begin() + index);
lastSpaceIndex = index;
}
}
}

Store sentence with punctuation in C++

It's my first time here and I am a beginner at C++. I would like to know how I can split sentences with punctuation mark while I am reading from a text file.
i.e.
hey how are you? The Java is great. Awesome C++ is awesome!
The result would be this in my vector (assuming I have put endl to display each content of the vector):
hey how are you?
The Java is great.
Awesome C++ is awesome!
Here's my code so far:
vector<string> sentenceStorer(string documentOfSentences)
{
ifstream ifs(documentOfSentences.c_str());
string word;
vector<string> sentence;
while ( ifs >> word )
{
char point = word[word.length()-1];
if (point == '.' || point == '?' || point == '!')
{
sentence.push_back(word);
}
}
return sentence;
}
void displayVector (vector<string>& displayV)
{
for(vector<string>::const_iterator i = displayV.begin(); i != displayV.end(); ++i )
{
cout << *i <<endl;
}
}
int main()
{
vector <string> readstop = sentenceStorer("input.txt");
displayVector(readstop);
return 0;
}
Here is my result:
you?
great.
awesome!
Can you explain why I couldn't get the previous word and fix that?
I will give you a clue. In while statement you have three conditions in the or clause. So if any of them is fulfilled than the while statement do not check other ones. So it takes your first and looks for . (dot). Then after finding it, reads it into the word, so in fact it omits question mark.
It looks you need to find other way to solve this. If I were you, I would read whole line and parse it char by char. As far as I am concerned there is no build-in string function that splits words by delimiter.

How to Read from a Text File, Character by Character in C++

I was wondering if someone could help me figure out how to read from a text file in C++, character by character. That way, I could have a while loop (while there's still text left) where I store the next character in the text document in a temp variable so I could do something with it, then repeat the process with the next character. I know how to open the file and everything, but temp = textFile.getchar() doesn't seem to work.
You could try something like:
char ch;
fstream fin("file", fstream::in);
while (fin >> noskipws >> ch) {
cout << ch; // Or whatever
}
#cnicutar and #Pete Becker have already pointed out the possibility of using noskipws/unsetting skipws to read a character at a time without skipping over white space characters in the input.
Another possibility would be to use an istreambuf_iterator to read the data. Along with this, I'd generally use a standard algorithm like std::transform to do the reading and processing.
Just for example, let's assume we wanted to do a Caesar-like cipher, copying from standard input to standard output, but adding 3 to every upper-case character, so A would become D, B could become E, etc. (and at the end, it would wrap around so XYZ converted to ABC.
If we were going to do that in C, we'd typically use a loop something like this:
int ch;
while (EOF != (ch = getchar())) {
if (isupper(ch))
ch = ((ch - 'A') +3) % 26 + 'A';
putchar(ch);
}
To do the same thing in C++, I'd probably write the code more like this:
std::transform(std::istreambuf_iterator<char>(std::cin),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(std::cout),
[](int ch) { return isupper(ch) ? ((ch - 'A') + 3) % 26 + 'A' : ch;});
Doing the job this way, you receive the consecutive characters as the values of the parameter passed to (in this case) the lambda function (though you could use an explicit functor instead of a lambda if you preferred).
To quote Bjarne Stroustrup:"The >> operator is intended for formatted input; that is, reading objects of an expected type and format. Where this is not desirable and we want to read charactes as characters and then examine them, we use the get() functions."
char c;
while (input.get(c))
{
// do something with c
}
Here is a c++ stylish function your can use to read files char by char.
void readCharFile(string &filePath) {
ifstream in(filePath);
char c;
if(in.is_open()) {
while(in.good()) {
in.get(c);
// Play with the data
}
}
if(!in.eof() && in.fail())
cout << "error reading " << filePath << endl;
in.close();
}
//Variables
char END_OF_FILE = '#';
char singleCharacter;
//Get a character from the input file
inFile.get(singleCharacter);
//Read the file until it reaches #
//When read pointer reads the # it will exit loop
//This requires that you have a # sign as last character in your text file
while (singleCharacter != END_OF_FILE)
{
cout << singleCharacter;
inFile.get(singleCharacter);
}
//If you need to store each character, declare a variable and store it
//in the while loop.
Re: textFile.getch(), did you make that up, or do you have a reference that says it should work? If it's the latter, get rid of it. If it's the former, don't do that. Get a good reference.
char ch;
textFile.unsetf(ios_base::skipws);
textFile >> ch;
Assuming that temp is a char and textFile is a std::fstream derivative...
The syntax you're looking for is
textFile.get( temp );
There is no reason not to use C <stdio.h> in C++, and in fact it is often the optimal choice.
#include <stdio.h>
int
main() // (void) not necessary in C++
{
int c;
while ((c = getchar()) != EOF) {
// do something with 'c' here
}
return 0; // technically not necessary in C++ but still good style
}

Why doesn't this change the .txt file?

I'm trying to edit a text file to remove the vowels from it and for some reason nothing happens to the text file. I think it may be because a mode argument needs to be passed in the filestream.
[SOLVED]
Code:
#include "std_lib_facilities.h"
bool isvowel(char s)
{
return (s == 'a' || s == 'e' || s =='i' || s == 'o' || s == 'u';)
}
void vowel_removal(string& s)
{
for(int i = 0; i < s.length(); ++i)
if(isvowel(s[i]))
s[i] = ' ';
}
int main()
{
vector<string>wordhold;
cout << "Enter file name.\n";
string filename;
cin >> filename;
ifstream f(filename.c_str());
string word;
while(f>>word) wordhold.push_back(word);
f.close();
ofstream out(filename.c_str(), ios::out);
for(int i = 0; i < wordhold.size(); ++i){
vowel_removal(wordhold[i]);
out << wordhold[i] << " ";}
keep_window_open();
}
Reading and writing on the same stream results in an error. Check f.bad() and f.eof() after the loop terminates. I'm afraid that you have two choices:
Read and write to different files
Read the entire file into memory, close it, and overwrite the original
As Anders stated, you probably don't want to use operator<< for this since it will break everything up by whitespace. You probably want std::getline() to slurp in the lines. Pull them into a std::vector<std::string>, close the file, edit the vector, and overwrite the file.
Edit:
Anders was right on the money with his description. Think of a file as a byte stream. If you want to transform the file in place, try something like the following:
void
remove_vowel(char& ch) {
if (ch=='a' || ch=='e' || ch=='i' || ch =='o' || ch=='u') {
ch = ' ';
}
}
int
main() {
char const delim = '\n';
std::fstream::streampos start_of_line;
std::string buf;
std::fstream fs("file.txt");
start_of_line = fs.tellg();
while (std::getline(fs, buf, delim)) {
std::for_each(buf.begin(), buf.end(), &remove_vowel);
fs.seekg(start_of_line); // go back to the start and...
fs << buf << delim; // overwrite the line, then ...
start_of_line = fs.tellg(); // grab the next line start
}
return 0;
}
There are some small problems with this code like it won't work for MS-DOS style text files but you can probably figure out how to account for that if you have to.
Files are sort of like a list, a sequential byte stream. When you open the file you position the file pointer at the very start, every read/write repositions the file pointer in the file with an offset larger than the last. You can use seekg() to move back in the file and overwrite previous content. Another problem with your approach above is that there will probably be some delimiters between the words typically one or more spaces for instance, you will need to handle read/write on these too.
It is much easier to just load the whole file in memory and do your manipulation on that string then rewriting the whole thing back.
Are you sure your while loop is actually executing? Try adding some debugging output to verify that it's doing what you think it is.