search and replace with pointers - c++

Im trying to implement a 'search and replace all'. I have 2 pointers to monitor characters nclude
#include
#include
using namespace std;
const int BUFSIZE = 256;
const char * const SEARCH = "the";
const char * const REPLACE = "Who is John";
int main()
{
char buf[BUFSIZE];
Error(SOURCE_FILE);
//open file for append and update
fstream destination(DESTINATION_FILE,
ios_base::in | ios_base::out | ios_base::app);
//check if destination file is open
if (!destination.is_open())
Error(SOURCE_FILE);
bufPtr += length; //move bufPtr to point past the SEARCH
destination << bufPtr; //write rest of buf to destination
//destination.seekg(0);
//write lines from source to destination
//if(!(destination << buf << '\n'))
//Error(SOURCE_FILE);
}
source.close();
destination.close();
return 0;
}

You're not checking for the case where strstr() doesn't find the search string. It returns NULL in that case, and your while loop loop won't do the right thing in that case.

Related

How to find a string in a binary file?

I want to find a specific string "fileSize" in a binary file.
The purpose of finding that string is to get 4 bytes that next to the string because that 4 bytes contains the size of data that I want to read it.
The content of the binary file like the following:
The same string in another position:
Another position:
The following is the function that writes the data to a file:
void W_Data(char *readableFile, char *writableFile) {
ifstream RFile(readableFile, ios::binary);
ofstream WFile(writableFile, ios::binary | ios::app);
RFile.seekg(0, ios::end);
unsigned long size = (unsigned long)RFile.tellg();
RFile.seekg(0, ios::beg);
unsigned int bufferSize = 1024;
char *contentsBuffer = new char[bufferSize];
WFile.write("fileSize:", 9);
WFile.write((char*)&size, sizeof(unsigned long));
while (!RFile.eof()) {
RFile.read(contentsBuffer, bufferSize);
WFile.write(contentsBuffer, bufferSize);
}
RFile.close();
WFile.close();
delete contentsBuffer;
contentsBuffer = NULL;
}
Also, the function that searches for the string:
void R_Data(char *readableFile) {
ifstream RFile(readableFile, ios::binary);
const unsigned int bufferSize = 9;
char fileSize[bufferSize];
while (RFile.read(fileSize, bufferSize)) {
if (strcmp(fileSize, "fileSize:") == 0) {
cout << "Exists" << endl;
}
}
RFile.close();
}
How to find a specific string in a binary file?
I think of using find() is an easy way to search for patterns.
void R_Data(const std::string filename, const std::string pattern) {
std::ifstream(filename, std::ios::binary);
char buffer[1024];
while (file.read(buffer, 1024)) {
std::string temp(buffer, 1024);
std::size_t pos = 0, old = 0;
while (pos != std::string::npos) {
pos = temp.find(pattern, old);
old = pos + pattern.length();
if ( pos != std::string::npos )
std::cout << "Exists" << std::endl;
}
file.seekg(pattern.length()-1, std::ios::cur);
}
}
How to find a specific string in a binary file?
If you don't know the location of the string in the file, I suggest the following:
Find the size of the file.
Allocate memory for being able to read everything in the file.
Read everything from the file to the memory allocated.
Iterate over the contents of the file and use std::strcmp/std::strncmp to find the string.
Deallocate the memory once you are done using it.
There are couple of problems with using
const unsigned int bufferSize = 9;
char fileSize[bufferSize];
while (RFile.read(fileSize, bufferSize)) {
if (strcmp(fileSize, "filesize:") == 0) {
cout << "Exists" << endl;
}
}
Problem 1
The strcmp line will lead to undefined behavior when fileSize actually contains the string "fileSize:" since the variable has enough space only for 9 character. It needs an additional element to hold the terminating null character. You could use
const unsigned int bufferSize = 9;
char fileSize[bufferSize+1] = {0};
while (RFile.read(fileSize, bufferSize)) {
if (strcmp(fileSize, "filesize:") == 0) {
cout << "Exists" << endl;
}
}
to take care of that problem.
Problem 2
You are reading the contents of the file in blocks of 9.
First call to RFile.read reads the first block of 9 characters.
Second call to RFile.read reads the second block of 9 characters.
Third call to RFile.read reads the third block of 9 characters. etc.
Hence, unless the string "fileSize:" is at the boundary of one such blocks, the test
if (strcmp(fileSize, "filesize:") == 0)
will never pass.

How to copy text from one file to another and then turning the first letters of the text string into uppercase

I am trying to build a program that copies text from one .txt file to another and then takes the first letter of each word in the text and switches it to an uppercase letter. So far, I have only managed to copy the text with no luck or idea on the uppercase part. Any tips or help would be greatly appreciated. This is what I have so far:
int main()
{
std::ifstream fin("source.txt");
std::ofstream fout("target.txt");
fout<<fin.rdbuf(); //sends the text string to the file "target.txt"
system("pause");
return 0;
}
Try this, Take the file content to a string, then process it, and again write to the traget file.
int main()
{
std::ifstream fin("source.txt");
std::ofstream fout("target.txt");
// get pointer to associated buffer object
std::filebuf* pbuf = fin.rdbuf();
// get file size using buffer's members
std::size_t size = pbuf->pubseekoff (0,fin.end,fin.in);
pbuf->pubseekpos (0,fin.in);
// allocate memory to contain file data
char* buffer=new char[size];
// get file data
pbuf->sgetn (buffer,size);
fin.close();
locale loc;
string fileBuffer = buffer;
stringstream ss;
for (std::string::size_type i=0; i<fileBuffer.length(); ++i){
if(i==0)
ss << toupper(fileBuffer[i],loc);
else if (isspace(c))
ss << fileBuffer[i] << toupper(fileBuffer[++i],loc);
else
ss << fileBuffer[i];
}
string outString = ss.str();
fout << outString;
fout.close();
}
Instead of copying the entire file at once, you'll need to read part or all of it into a local "buffer" variable - perhaps using while (getline(in, my_string)), then you can simply iterate along the string capitalising letters that are either in position 0 or preceeded by a non-letter (you can use std::isalpha and std::toupper), then stream the string to out. If you have a go at that and get stuck, append your new code to the question and someone's sure to help you out....
I think for this copying the whole file is not going to let you edit it. You can use get() and put() to process the file one character at a time. Then figure out how to detect the start of a word and make it uppercase:
Something like this:
int main()
{
std::ifstream fin("source.txt");
std::ofstream fout("target.txt");
char c;
while(fin.get(c))
{
// figure out which chars are the start
// of words (previous char was a space)
// and then use std::toupper(c)
fout.put(c);
}
}
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main() {
FILE* fpin;
FILE* fpout;
int counter = 0;
char currentCharacter;
char previousCharacter=' ';
fpin = fopen("source.txt", "r"); /* open for reading */
if (fpin == NULL)
{
printf("Fail to open source.txt!\n");
return 1;
}
fpout = fopen("target.txt", "w");/* open for writing */
if (fpout == NULL)
{
printf("Fail to open target.txt!\n");
return 1;
}
/* read a character from source.txt until END */
while((currentCharacter = fgetc(fpin)) != EOF)
{
/* find first letter of word */
if(!isalpha(previousCharacter) && previousCharacter != '-' && isalpha(currentCharacter))
{
currentCharacter = toupper(currentCharacter); /* lowercase to uppercase */
counter++; /* count number of words */
}
fputc(currentCharacter, fpout); /* put a character to target.txt */
/* printf("%c",currentCharacter); */
previousCharacter = currentCharacter; /* reset previous character */
}
printf("\nNumber of words = %d\n", counter);
fclose(fpin); /* close source.txt */
fclose(fpout); /* close target.txt */
return 0;
}

extract words (made of unsigned characters) from a file with a delimiter in c++

I have been searching over internet, but could not find any existing tools for extracting words from a file with a specific delimiter in C++. Does anyone know an already existing library or code in C++ that does the job. Given below is what I wanted to achieve :
Objective : to extract words from a file using a delimiter
Words type : words can be made of any combination of unsigned characters (within UTF-8 encoding set). So, \0 should also be considered as a character. And only delimiter should be able to separate any two words from each other.
File type : text file
I have tried the following code :
#include <iostream>
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;
#include <cstring>
const int MAX_TOKENS_PER_FILE = 100000;
const int MAX_CHARS_PER_LINE = 512;
const int MAX_TOKENS_PER_LINE = 256;
const char* const DELIMITER = " ";
int main()
{
int index = 0, keyword_num = 0;
// stores all the words that are in a file
unsigned char *keywords_extracted[MAX_TOKENS_PER_FILE];
// create a file-reading object
ifstream fin;
fin.open("data.txt"); // open a file
if (!fin.good())
return 1; // exit if file not found
// read each line of the file
while (!fin.eof())
{
// read an entire line into memory
char buf[MAX_CHARS_PER_LINE];
fin.getline(buf, MAX_CHARS_PER_LINE);
// parse the line into blank-delimited tokens
int n = 0; // a for-loop index
// array to store memory addresses of the tokens in buf
const char* token[MAX_TOKENS_PER_LINE] = {}; // initialize to 0
// parse the line
token[0] = strtok(buf, DELIMITER); // first token
if (token[0]) // zero if line is blank
{
keywords_extracted[keyword_num] = (unsigned char *)token[0];
keyword_num++;
for (n = 1; n < MAX_TOKENS_PER_LINE; n++)
{
token[n] = strtok(0, DELIMITER); // subsequent tokens
if (!token[n]) break; // no more tokens
keywords_extracted[keyword_num] = (unsigned char *)token[n];
keyword_num++;
}
}
}
// process (print) the tokens
for(index=0;index<keyword_num;index++)
cout << keywords_extracted[index] << endl;
}
But I have a problem from the above code :
The first word/entry in keywords_extracted is being replaced with '0' as the the content of the last line the program reads is empty.(correct me if i'm doing/assuming anything wrong).
Is there a way to overcome this problem in the above code or are any other existing libraries for this functionality? Sorry for lengthy explanation, just trying to be clear.
std::getline takes a delimiter (3rd argument) which can be different than the default '\n' -- does that not work for you?
Example;
std::string word;
while (std::getline(fin, word, '|')) {
std::cout << word;
}
should read and print every word using pipe (|) as the seperator

const char* not passing full filename

I know there are a lot of questions similar to this, but I don't know of any that are the same, so here's my issue:
I'm trying to pass a filename as a const char * to my ifstream to read and load.
BUT: When I pass the filename, instead of reading the whole string "map.obj"; it just reads the first character "m" and as a result, the ifstream fails.
I don't know what I'm doing wrong and would appreciate a little help. My code follows:
#include <fstream>
using namespace std;
void loadModel(const char* filename);
int main()
{
// Creates and positions the four boxes on the screen. Temporary.
//rotation r = {0.0f, 0.0f, 0.0f};
const char* filename = "map.obj";
loadModel(filename);
return 0;
/*meshMgr.addObject(new Object());
position p = {0.f, 10.f, 10.f};
meshMgr.addObject(new Object(p, r));
p.y = 0.f;
p.z = 20.f;
meshMgr.addObject(new Object(p, r));
p.y = -10.f;
p.z = 10.f;
meshMgr.addObject(new Object(p, r));*/
}
void loadModel(const char* filename)
{
ifstream in(filename, ios::in); //Open the model file
if (in.is_open()) //if not opened, exit with -1
{
//Set up an array to act as a buffer for text read from the input file
char buf[256];
//Read input file text to end of file and push onto lines list
while (!in.eof())
{
in.getline(buf, 256);
//lines.push_back(new std::string(buf));
}
in.close();
}
}
EDIT: Before anyone asks, yes the file is being referenced as a local file (do I need to use absolute paths or something?) and exists in the same directory as the source code
As a response to my own question, it appears that my code didn't like passing the variable that stored the filename as a cost char * when the data in the variable was stored in a string-like format.
To counteract this, I simply changed the code from:
int main ()
{
...
const char* filename = "map.obj";
loadModel(filename);
...
return 0;
}
void loadModel(const char* filename)
{
...
}
to the following:
int main ()
{
...
string filename = "map.obj";
loadModel(filename);
...
return 0;
}
void loadModel(string filename)
{
...
}
where "..." indicates more code as shown in the question.
This answers the error in the question, but begins with a string instead and uses a char instead of const char*. It's an alternative solution.
const char* not passing full filename
std::string filename = "map.obj";
char *cstr = new char[filename.length() + 1];

Trouble with seekp() to replace portion of file in binary mode

I'm having some trouble with replacing a portion of a file in binary mode. For some reason my seekp() line is not placing the file pointer at the desired position. Right now its appending the new contents to the end of the file instead of replacing the desired portion.
long int pos;
bool found = false;
fstream file(fileName, ios::binary|ios::out|ios::in);
file.read(reinterpret_cast<char *>(&record), sizeof(Person));
while (!file.eof())
{
if (record.getNumber() == number) {
pos=file.tellg();
found = true;
break;
}
// the record object is updated here
file.seekp(pos, ios::beg); //this is not placing the file pointer at the desired place
file.write(reinterpret_cast<const char *>(&record), sizeof(Person));
cout << "Record updated." << endl;
file.close();
Am I doing something wrong?
Thanks a lot in advance.
I don't see how your while() loop can work. In general, you should not test for eof() but instead test if a read operation worked.
The following code writes a record to a file (which must exist) and then overwrites it:
#include <iostream>
#include <fstream>
using namespace std;
struct P {
int n;
};
int main() {
fstream file( "afile.dat" , ios::binary|ios::out|ios::in);
P p;
p.n = 1;
file.write( (char*)&p, sizeof(p) );
p.n = 2;
int pos = 0;
file.seekp(pos, ios::beg);
file.write( (char*)&p, sizeof(p) );
}
while (!file.eof())
{
if (record.getNumber() == number) {
pos=file.tellg();
found = true;
break;
}
here -- you`re not updating number nor record -- so basically you go through all file and write in "some" location (pos isn't inited)
And Neil Butterworth is right (posted while i typed 8)) seems like you omitted smth