I am trying to write a "censor" program. here are the instructions:

Write a program that reads a file of text and replaces each `target'
word with its first letter followed by a string of asterisks that indicate
its length. Have it read the list of target words from a file, so that new
words to censor can be added. Allow words to be separated by newlines,
blanks, tabs, formfeeds, and punctuation symbols like commas, periods, single
and double quotes, and parentheses.

And here's what I've got so far:

#include <string>
#include <fstream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <iterator> 
using namespace std;

int words();
void censor(const vector<string>& x, int);
void write_to_file( const vector<string>& message);

int main(){
    words();
    system ("pause");
}
    
  int  words (){
    int count =0;
    std::vector<std::string> file;
    std::string line;
    file.clear();
    std::ifstream infile ("words.txt", std::ios_base::in);
    while (getline(infile, line, '\n'))
    {
        file.push_back (line);
        count ++;
    }
   censor(file, count);
}

void censor(const vector<string>& inFile, int count)
{
    int messagecount =0;
    std::vector<std::string> message;
    std::string messageword;
    message.clear();
    std::ifstream infile ("myfile.txt", std::ios_base::in);
    while (getline(infile, messageword, '\n'))
    {
        message.push_back (messageword);
        messagecount++;
    }   
    for (int k=0; k < messagecount; k++)
    {
        for (int h=0;h < count ; h++)
        {
            if (inFile[h]== message[k])
            {   
                   message[k] = "******";
            }
         }
     }
     cout << "calling write\n ";
     write_to_file(message);
}

void write_to_file(const vector<string>& message)
{
        std::fstream messageFile ("myfile.txt", std::ios_base::out);
        for (int y=0; y < message.size() ; y++ )
        {
            messageFile << message[y] << ' ';
        }
}

So my problem is with "(getline(infile, messageword, '\n'))". Is there any way to have more than one delimiter in this? To allow for "newlines, blanks, tabs, formfeeds, and punctuation symbols like commas, periods, single and double quotes, and parentheses"? I was just trying to get the basics before worrying about all that. I tried putting two conditions in the line, something like
"(getline(infile, messageword, '\n' || ' '))", but that doesn't work.

Recommended Answers

All 18 Replies

I have solved that problem, now have another. How do I replace all letters but the first with an asterisk? I don't know how to do this in a vector.

#include <string>
#include <fstream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <iterator> 
using namespace std;

int words();
void censor(vector<string>& x, int);
void write_to_file( vector<string>& message);

int main()
{
    words();
    system ("pause");
}
    
int  words (){
    int count =0;
    std::vector<std::string> file;
    std::string line;
    file.clear();
    std::ifstream infile ("words.txt", std::ios_base::in);
    while (infile >> line)
    {
        file.push_back (line);
        count ++;
    }
   censor(file, count);
}

void censor( vector<string>& inFile, int count)
{
    int messagecount =0;
    std::vector<std::string> message;
    std::string messageword;
    message.clear();
    std::ifstream infile ("myfile.txt", std::ios_base::in);
    while (infile >> messageword)
    {
        message.push_back (messageword);
        messagecount++;
    }   
    for (int k=0; k < messagecount; k++)
    {
        for (int h=0;h < count ; h++)
        {
            if (inFile[h]== message[k])
            {      
                   
                   cout <<"Changing " << message[k] << endl;
                  /* int len = sizeof(message[k]);
                   for(int r = 1; r< len; r++){*/
                   message[k] = "*";
                   //}
            }
         }
     }
     cout << "Calling write\n ";
     write_to_file(message);
}

void write_to_file( vector<string>& message)
{
        std::fstream messageFile ("myfile.txt", std::ios_base::out);
        for (int y=0; y < message.size() ; y++ )
        {
            messageFile << message[y] << ' ';
        }
}

use a loop

string word = "Hello";
for(int i = 1; i < word.length(); i++)
   word[i] = '*';

How do I use that in this program, where I am trying to change a string in a vector that already has []?

I suppose you replace line 56 with this:

string& word = message[k];
// now the rest of that alrorithm

I see. Now the only problem I have is the writing back to the file. i want it to be formatted the way it was in the original file. Now I only have everything seperated by a space. How can I do that?

You have lost the line terminators '\n' because at line 41 it is reading one word at a time. You will have to rethink the logic of that program so that it can still see end-of-line '\n'.

I think the easiest way to do it is to read the input file one line at a time, use stringstream to split it into words, check the word to see if it needs to be converted to asterisks, then finally write the word to the output file. You don't need to use vector at all in this process, nor do you need to write additional functions.

string line;
string word;
open both input and output files
while( getline( infile, line )
{
    stringstream stream( line );
    while( stream >> word )
    {
         // convert just this one word before
         Search words.txt to see if word needs to be changed
               change the word to asterisks
         write the word to output file
    }
    write '\n' to the output file
}
close input and output files

That is how I started, but I was having a problem writing just the censored word to the file. I was advised on another forum that the only way to write one word to a file is to use vectors, and that's how my program became the monster it is now. If I were to do that, how could I overwrite one word in the middle of a file?

You have to write the words to another file, not the same input file, similar to below. The code below doesn't change anything but just writes whatever was read to the output file.

ifstream in("infile.txt");
ofstream out("outfile.txt");
while( getline(in, line)
{
     stringstream stream(line);
     while( stream >> word)
     {
            // convert the word if needed is not shown here
            out << word << " ";
     }
     out << "\n";
}

The above will replace all spaces and tabs between words with a single space. So

how                     now

will wind up as

how now

Right, but I want to keep the spaces and everything else. Is there any way to do that?

instead of reading one line at a time, read one character at a time. when a white-space character is read that's the end of a word. Process the word, write to the file as previously shown, then just read/write each charcter until the next non-white-space character is read, something like this I suppose. I didn't compile or test it, but will probably work.

char ch;
string word;
while( infile.get(ch) )
{
   if( !isspace(ch) )
        word += ch;
   else
   {
          // end of word, so process it and write it to file
          outfile << word;
          word = "";
         while( infile.get(ch)  && isspace(ch) )
             outfile << ch;
         word = ch;  // save 1st letter of the word
   }
}

After re-readingt he instructions, I don't think I'm allowed to write to a new file. So I'm trying to use your example and write over the same file. I'm confused. Here's what I have:

#include <string>
#include <fstream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <iterator> 
using namespace std;

int main()
{
    string messageword;
    fstream messagefile("myfile.txt");
    int bannedcount =0;
    std::vector<std::string> bannedfile;
    std::string line;
    bannedfile.clear();
    std::fstream infile ("words.txt", std::ios_base::in | ios::out);
    while (infile >> line)
    {
        bannedfile.push_back (line);
        bannedcount ++;
    }
    char ch;
    while( messagefile.get(ch) )
    {
           if( !isspace(ch) )
               messageword += ch;
           else
           {
             for (int h=0; h < bannedcount ; h++)
             {
                 cout << "Word is " << messageword << " and banned is " << bannedfile[h] << endl;
                 if (messageword == bannedfile[h])
                 {     
                   cout <<"Changing " << bannedfile[h] << endl;
                   for(int i = 1; i < messageword.length(); i++)
                   {
                           messageword[i] = '*';
                   } 
                 
                 }
             
             
             cout << "writing!\n";
             messagefile << messageword;
             cout << "written!\n";
             }
             messageword = "";
             while( messagefile.get(ch)  && isspace(ch) ){
                        messagefile << ch;
                 }
                 messageword = ch;  // save 1st letter of the word*/
    }
}
    system ("pause");
}

I don't understand the last part of your loop. How do I continue on to the next word in the file?

>>I'm confused
No supprised, because you can't write directly to the same file. What makes you think your instructions tell you to output to the same input file?

What is possible is output to a different file. Then when done, close both files, delete the original input file, then rename the output file to the filename of the original input file.

I was writing to the same file when using this code:

#include <string>
#include <fstream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <iterator> 
using namespace std;

void words();
void censor(vector<string>& , int);
void write_to_file( vector<string>& );


int ast_length=0;
char *ast;

int main()
{
    words();
    system ("pause");
}
    
void  words ()
{
    int count =0;
    std::vector<std::string> file;
    std::string line;
    file.clear();
    std::ifstream infile ("words.txt", std::ios_base::in);
    while (infile >> line)
    {
        file.push_back (line);
        count ++;
    }
   censor(file, count);
}

void censor( vector<string>& inFile, int count)
{
    int messagecount =0;
    std::vector<std::string> message;
    std::string messageword;
    message.clear();
    std::ifstream infile ("myfile.txt", std::ios_base::in);
    while (infile >> messageword)
    {
        message.push_back (messageword);
        messagecount++;
    }   
    for (int k=0; k < messagecount; k++)
    {
        for (int h=0;h < count ; h++)
        {
            if (inFile[h]== message[k])
            {      
                   cout <<"Changing " << message[k] << endl;
                   string& word = message[k];
                   for(int i = 1; i < word.length(); i++)
                   {
                   word[i] = '*';
                   }
                   
                   message[k] = word;
            }
         }
     }
     cout << "Calling write...\n ";
     write_to_file(message);
}

void write_to_file( vector<string>& message)
{
        std::fstream messageFile ("myfile.txt", std::ios_base::out|std::ios_base::in);
        for (int y=0; y < message.size() ; y++ )
        {
            messageFile << message[y] << ' ';
        }
        
}

Since the instructions just say "replace" the words, it makes it seem like I should change them in that file.

Reading the entire file into memory then rewriting it will work on small files. But doesn't work very well on huge files because of the large amount of memory it will take up and the amount of time it takes to load those vectors. How will that program work on a multi-megabite file ?

>>Right, but I want to keep the spaces and everything else. Is there any way to do that?
And your last post doesn't do that either.

I see what you mean, but this is just a project for a beginning programming class, so I'm not concerned with that. I'm pretty sure this is what he wants me to do.
Funny quote, by the way!

Do it however you want, but you still won't be able to maintain the spacing and tabs of the original program that way because the >> operator skips over them.

Thats why Im trying to use your getchar idea into this code.

I'm sorry, I didn't see what you had written before about deleting and renaming. That would be good! (I've been in front of the computer for too long). Here's my attempt:

#include <string>
#include <fstream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <iterator> 

using namespace std;

int main()
{
    char ch;
    string word ="";
    ifstream messagefile("myfile.txt");
    ofstream out("outfile.txt");
    int bannedcount =0;
    std::vector<std::string> bannedfile;
    std::string line;
    bannedfile.clear();
    std::ifstream infile ("words.txt", std::ios_base::in);
    while (infile >> line)
    {
        bannedfile.push_back (line);
        bannedcount ++;
    }
    while( messagefile.get(ch) )
    {
       do
       {
           word += ch;
           messagefile.get(ch);
       }
       while ( isalpha(ch) );
       for (int h=0; h < bannedcount ; h++)
       {
                  cout << "\nword is " << word << endl;
       cout << "\nbanned is " << bannedfile[h];
             if (word== bannedfile[h])
             {      
                   cout <<"Changing " << bannedfile[h] << endl;
                   for(int i = 1; i < word.length(); i++)
                   {
                          word[i] = '*';
                   } 
             }
       }
       out << word;
       while( infile.get(ch)  && isspace(ch) )
             out << ch;
       word = ch; 
    }
    messagefile.close();
    out.close();
    /*system("del myfile.txt");
    int result;
    char oldname[] ="outfile.txt";
    char newname[] ="myfile.txt";
    result= rename( oldname , newname );
    if ( result == 0 )
       puts ( "File successfully renamed" );
    else
       perror( "Error renaming file" );*/
       system ("pause");
}

This keeps the formatting and writes to an output file.
The problem with this is the spaces make the words different.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.