Sign in to follow this  

Search and Replace Function

This topic is 4342 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm looking for a simple search and replace function written in C, but have been unable to find one. Does anyone know of a free one that works? I want to be able to give it a string like "Jack and Jill went over the hill." and tell it to replace all occurences of "Jack" with something like "John Thomas". I've written my own, but it has stopped working since I upgraded my compiler.

Share this post


Link to post
Share on other sites
Quote:
Original post by Davaris
I've written my own, but it has stopped working since I upgraded my compiler.


Post your code (and tell us which compiler you are using) and we can help you find the problem.

Alan

Share this post


Link to post
Share on other sites
Okay. The Compiler I am using is Vis C++ 2005 Express. The one I was using before was Vis C++ 5.0, which I'm told wasn't too great. The only thing I've changed is the line strcpy_s (pdest, new_len, psrc1); as strcpy had to upgraded to the secure version.

This is what my memory manager is telling me:
*********************************************************************
A memory allocation unit was corrupt because of an overrun:
Address (reported): 03666398
Address (actual) : 03666388
Size (reported) : 0x00000014 ( 20 bytes )
Size (actual) : 0x00000034 ( 52 bytes )
Owner : stringc.cpp(1141)::STRINGC2::SearchAndReplace
Allocation type : new[]
Allocation number : 365322

*********************************************************************

//This is the data for the string class

class STRINGC2
{
private:
char* Str;
STRINGC2* Next; // ignore this. It isn't used in search and replace
}

*********************************************************************


bool STRINGC2::SearchAndReplace (STRINGC2 src, STRINGC2 search, const STRINGC2& replace, STRINGC2* dest)
{
const char* psrc1;
const char* psrc2;
char* pdest;
int num;
int search_len = search.Len();
int replace_len = replace.Len();
int search_cnt = 0;

// Count the number of search
psrc1 = (const char*) src;

while ((psrc2 = strstr (psrc1, (const char*)search.Str)))
{
psrc1 = psrc2 + replace_len;
search_cnt++;
}

if (search_cnt == 0) return false;

// Create a string of correct size
int new_len = src.Len() - search_cnt*search_len + search_cnt*replace_len;

FREE_ARRAY (dest->Str);
FREE (dest->Next);
dest->Str = new char [new_len + 1]; // this is line 1141


// Go through and replace without reallocing
psrc1 = (const char*) src;
pdest = dest->Str;

memset(pdest, 'x', new_len); // debug

while ((psrc2 = strstr (psrc1, (const char*) search)))
{
num = psrc2 - psrc1;
memcpy (pdest, psrc1, num);

psrc1 = psrc2 + search_len;

pdest += num;
memcpy(pdest, (const char*)replace, replace_len);
pdest += replace_len;
}

strcpy_s (pdest, new_len, psrc1);

return true;
}


int STRINGC2::Len () const
{
return strlen (Str);
}

*********************************************************************

Share this post


Link to post
Share on other sites
Why not use C++?

Here is an example of a SearchAndReplace function that is somewhat generic. It can be used on std::string, std::vector, std::list, std::deque, and any container you write with a few properties:
#include <string>
#include <algorithm>
#include <functional>
#include <iterator>

//Searches the container 'SearchHere' for 'FindThis' and replaces it with 'Replacement'
//The predicate 'Pred' is used to compare elements in the container for equality,
// and impose an equivalence relation between its operands.
template <typename ContainerType, typename PredicateType>
ContainerType FindAndReplace(const ContainerType &p_SearchHere,
const ContainerType &p_FindThis, const ContainerType &p_Replacement,
PredicateType p_Pred)
{
//Constants to store various boundaries
const ContainerType::const_iterator FindThisBegin = p_FindThis.begin();
const ContainerType::const_iterator FindThisEnd = p_FindThis.end();
const ContainerType::size_type FindThisSize = p_FindThis.size();
const ContainerType::const_iterator ReplacementBegin = p_Replacement.begin();
const ContainerType::const_iterator ReplacementEnd = p_Replacement.end();
const ContainerType::const_iterator SearchHereBegin = p_SearchHere.begin();
const ContainerType::const_iterator SearchHereEnd = p_SearchHere.end();

//Iterators to step through the 'SearchHere' string
ContainerType::const_iterator SearchStart = SearchHereBegin;
ContainerType::const_iterator FoundPosition = SearchStart;

//Container to store the original container with replacements
ContainerType Result;

//Back Inserter Iterator to append elements to Result
std::back_insert_iterator<ContainerType> ResultInserter = std::back_inserter(Result);

do{
//Find the next match in 'SearchHere'
FoundPosition = std::search(SearchStart, SearchHereEnd, FindThisBegin, FindThisEnd, p_Pred);
//Copy the text between the last match and this match
std::copy(SearchStart, FoundPosition, ResultInserter);

//Advance the start position to this match
SearchStart = FoundPosition;
//If there was a match,
if(SearchStart != SearchHereEnd)
{
//Copy the replacement string instead of the match
std::copy(ReplacementBegin, ReplacementEnd, ResultInserter);
//Advance past this match so it won't be found again
std::advance(SearchStart, FindThisSize);
}
//Otherwise, exit loop
}while(FoundPosition != SearchHereEnd);
//Return original container with replacements made
return Result;
}

//Searches the container 'SearchHere' for 'FindThis' and replaces it with 'Replacement'
//The predicate 'std::equal_to' is used to compare elements in the container for equality,
// and impose an equivalence relation between its operands.
template <typename ContainerType>
ContainerType FindAndReplace(const ContainerType &p_SearchHere,
const ContainerType &p_FindThis, const ContainerType &p_Replacement)
{
//If no predicate is given, use std::equal_to instead
return FindAndReplace(p_SearchHere, p_FindThis, p_Replacement, std::equal_to<ContainerType::value_type>());
}

It's probably pretty scary if you're not used to those header, but it's very easy to use:
#include <iostream>
using namespace std;

int main(void)
{
string SomeText = "Replace all instances of 'a' with four, except for those instances followed by an 'n', which become '@' instead.";

cout << "Before:" << endl << SomeText << endl << endl;

SomeText = FindAndReplace<string>(SomeText, "an", "@n");
cout << "Between:" << endl << SomeText << endl << endl;

SomeText = FindAndReplace<string>(SomeText, "a", "4");
cout << "After:" << endl << SomeText << endl << endl;
return 0;
}
The output:
Before:
Replace all instances of 'a' with four, except for those instances followed by an 'n', which become '@' instead.

Between:
Replace all inst@nces of 'a' with four, except for those inst@nces followed by @n 'n', which become '@' instead.

After:
Repl4ce 4ll inst@nces of '4' with four, except for those inst@nces followed by @n 'n', which become '@' inste4d.

Share this post


Link to post
Share on other sites
Quote:

dest->Str = new char [new_len + 1]; // this is line 1141


Hello C++.

Quote:
Original post by Extrarius
Why not use C++?


Yes, let's *really* use it ok? char*'s are just asking for trouble for this sort of thing. The standard library will provide. There's really no excuse for not using the standard library for the language you are programming in. You wouldn't eschew printf() et al. in C, right? Well, if you allocate with 'new', then you might not be writing proper C++, but you sure as hell aren't writing any kind of C. :)

Anyway, if you don't need anything that generic, you should be able to use something like this with std::string:


void searchAndReplace(const std::string& what, const std::string& with, std::string& in) {
int pos = 0;
int whatLen = what.length();
int withLen = with.length();
while ((pos = in.find(what, pos)) != std::string::npos) {
in.replace(pos, whatLen, with);
pos += withLen;
}
}

Share this post


Link to post
Share on other sites

This topic is 4342 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this