Finding index of needle in haystack recursively. - c++

I am pretty close to completing my function. I need to take 2 strings, and return the index of string 2 inside of string 1. I know there is a find function for this, but I am not able to use it. It also has to be done with recursive programming.
I have the following.
int index_of(string haystack, string needle) {
int index = 0;
string test = haystack.substr(index, needle.length());
if (test == needle) {
return index;
}
else {
return 1 + index_of(haystack.substr(1), needle);
}
}
It returns the index of the needle in the haystack no problem but there are 2 things it needs to do I can not figure out.
1) If the needle is not in the haystack, then it needs to return a -1. I have done it so at the end if it does not exist, it returns a -1, but because it is recursive, it then adds the other times it returned 1. I am not sure how to just return a single value at the end without adding all the other instances on it.
2) I am suppose to use a helper function within it and I am not sure how to do that either.
Thanks for any help!

In general, you want to return the value of a recursive function unadulterated. In your case, this:
return 1 + index_of(some_parameters);
Should be this:
return index_of(some_parameters);
Now, you just need to choose parameters such that you can keep track of the index until you need to return it, or alternatively -1.
One such function might have the constructor:
index_of(string haystack, string needle, int index);

Here is a demonstrative program that shows how the function can be implemented.
#include <iostream>
#include <string>
std::string::size_type index_of( std::string haystack, const std::string &needle )
{
if ( haystack.size() < needle.size() ) return std::string::npos;
if ( haystack.compare( 0, needle.size(), needle ) == 0 ) return 0;
std::string::size_type index;
return ( index = index_of( haystack.substr( 1 ), needle ) ) == std::string::npos ? index : ++index;
}
int main()
{
std::string haystack( "asdfghjkl" );
std::string needle( "gh" );
std::string::size_type index = index_of( haystack, needle );
if ( index != std::string::npos )
{
std::cout << "string \"" << needle
<< "\" is found in string \"" << haystack
<< "\" at position " << index
<< std::endl;
}
else
{
std::cout << "string \"" << needle
<< "\" is not found in string \"" << haystack << "\""
<< std::endl;
}
}
Its output is
string "gh" is found in string "asdfghjkl" at position 4
Of course the simplest approach is to define a static variable that would keep the current position in the source string. But in this case I do not think that such a function is a "pure recursive".

Related

Replace a subString in an std::string but not all of them using C++

I'm new to C++, I know that my post can be found duplicate with other posts but what I want to do is that to replace a substring in a string but not all of them.
This is my find and replaces substring function, it's worked like the other replace function:
void findAndReplaceAll(std::string& data, std::string toSearch, std::string replaceStr)
{
//Get the first occurrence
size_t pos = data.find(toSearch);
//Repeat till end is reached
while (pos != std::string::npos)
{
//Replace this occurrence of Sub String
data.replace(pos, toSearch.size(), replaceStr);
//Get the next occurrence from the current position
pos = data.find(toSearch, pos + replaceStr.size());
}
}
My main function:
int main()
{
std::string format = "h 'o''cloch' a, zzzz";
findAndReplaceAll(format, "h", "%h");
return 0;
}
The output that I want is just to replace the first 'h' but not the second 'h' one.
"%h 'o''cloch' a,zzzz";
You can add an argument to your function that tells after how many characters you need to stop replacing substrings.
The function prototype would look something like this: void findAndReplaceAll(std::string& data, std::string toSearch, std::string replaceStr, int stopAfterXCharacters).
You would then need to change your while loop to stop when that certain amount of characters has been read.
Alternatively, you could have a function that only replaces a certain amount of substrings, and in your case your function would return if one substring has been changed.
You can write a separate function that replaces only one found string.
Here is a demonstrative program
#include <iostream>
#include <string>
bool findAndReplace( std::string &data,
const std::string &toSearch,
const std::string &replaceStr,
std::string::size_type pos = 0 )
{
bool success = pos < data.size();
if ( success )
{
success = ( pos = data.find( toSearch, pos ) ) != std::string::npos;
if ( success )
{
data.replace( pos, toSearch.size(), replaceStr );
}
}
return success;
}
int main()
{
std::string format = "h 'o''cloch' a, zzzz";
findAndReplace( format, "h", "%h" );
std::cout << "\"" << format << "\"\n";
return 0;
}
Its output is
"%h 'o''cloch' a, zzzz"

how to point to delimiter at fixed position in std::string

Say I have text say with '#' as a delimiter.
example
std::string key = "012#txt1#txt2#txt3#txt4# #some other text:"
I have to insert modified text between #at position 5 and #at position 6. The one shown above with spaces in between.
To accomplish this I need to find 5th # and 6th #.
I wrote a small code but its not doing what i expect to do.It always return first found '#'. can someone please advice me.
std::string temp = key;
size_t found = 0;
size_t pos_key = temp.find('#');
while( ( found !=5 )&& ( pos_key != std::string::npos ) )
{
found++;
temp.find_first_of('#', pos_key + 1 );
temp.erase(0, pos_key );
}
std::cout << " the pos key is " << pos_key << std::endl ;
There are a couple problems going on. first you never update pos_key so you are stomping all over your string when you call erase which I am not sure why you are doing that. If you need to find the nth symbol you can use a function like:
size_t find_nth(const std::string & line, const std::string & symbol, size_t nth)
{
size_t pos = 0;
size_t counter = 0;
while (counter < nth && (pos = line.find(symbol, pos)) != std::string::npos)
{
counter++; // found a match so increment
pos++; // increment so we search for the next one
}
return pos;
}
And you can see it running in this Live Example
It seems you have two problems.
First you are not remembering the position of the '#' when you find it, you need to assign the return value of the std::string::find_first_of function to pos_key.
Second you keep deleting the contents of the string up to the position you find. That throws off all the position information you got from the std::string::find_first_of function.
I think this might be what you need:
int main()
{
std::string key = "012#txt1#txt2#txt3#txt4# #some other text:";
std::string temp = key;
size_t found = 0;
size_t pos_key = temp.find('#');
while((found != 5) && (pos_key != std::string::npos))
{
found++;
// this line does nothing with the found position
// temp.find_first_of('#', pos_key + 1);
// instead record the position of the latest '#'
pos_key = temp.find_first_of('#', pos_key + 1);
// this line just deletes most of the string
// for no apparent reason
// temp.erase(0, pos_key);
}
std::cout << " the pos key is " << pos_key << std::endl;
}

Recursively find a string within a string in C++

(C++)
Given myString, I want to check if myString contains substring. Here's what I have so far, but it only returns true if the string begins with the substring.
bool find(string myString, string substring)
{
if(mystring.length() < substring.length())
{
return false;
}
if(mystring == substring)
{
return true;
}
for(int i = 0; i < substring.length() - 1 ; ++i)
{
if(mystring.at(i) == substring.at(i))
{
continue;
}
else
{
string string2 = mystring.substr(1, mystring.length() - 1);
return find(string2, substring);
}
return true;
}
return false;
}
What is wrong with this function?
Check this function, it based on your code, with removal of extra code and fix of the errors.
I also changed the signature to get const reference to improve the efficiency.
bool find(const string& myString, const string& substring)
{
if(myString.length() < substring.length()){
return false;
}
else if(myString.substr(0,substring.size()) == substring){
return true;
}
else if (myString.length() > substring.length()){
return find(myString.substr(1), substring);
}
else{
return false;
}
}
First of all the function can be written simpler. For example
bool find( const std::string &myString, const std::string &subString )
{
return
( myString.substr( 0, subString.size() ) == subString ) ||
( subString.size() < myString.size() && find( myString.substr( 1 ), subString ) );
}
Here is a demonstrative program
#include <iostream>
#include <iomanip>
#include <string>
bool find( const std::string &myString, const std::string &subString )
{
return
( myString.substr( 0, subString.size() ) == subString ) ||
( subString.size() < myString.size() && find( myString.substr( 1 ), subString ) );
}
int main()
{
std::cout << std::boolalpha << find( "Hello World", "World" ) << std::endl;
std::cout << std::boolalpha << find( "Hello C", "C++" ) << std::endl;
}
The program output is
true
false
As for your function then it will return true only in the case when the both string have the same length and are equal each other
if(myString == substring){
return true;
}
And in case when myString.length() > substring.length() the function returns nothing
else if (myString.length() > substring.length()){
int start = 1;
int end = (int) myString.length() - 1;
string string2 = myString.substr(start, end);
find(string2, substring);
}
I think you mean
return find(string2, substring);
in this code snippet.
EDIT: I see that you changed the code of the function in your post. But in any case this code snippet
for(int i = 0; i < substring.length() - 1 ; ++i)
{
if(mystring.at(i) == substring.at(i))
{
continue;
}
else
{
string string2 = mystring.substr(1, mystring.length() - 1);
return find(string2, substring);
}
return true;
}
makes no sense.
You're missing a return before the recursive call to find. As it stands it falls through to the return false at the end.
Also, if (mystring == substring) should be checking if mystring starts with substring, not exact equality.
First, this is expensive because of the memory copies in substr.
Second, you havent checked for substring length > 0.
Third, the "else if" check for mystring.length > 0 is redundant if you have done the other checks (including substring length > 0).
Now to your core logic. In the recursion your start is never moving, so you are tied to the beginning. What you need to do is start with position 1, and increment start at every recursion, and also extract using substr the substring from "start" to "start + substring.length". That way you start from the beginning, keep moving forward, and check the correct length. You could also start from the end (as you have) and move back, what you would have to do there is: find sart position (end position minus length of substring), and check that the start position is not less than zero before calling the function recursively.
You're just removing the leftmost characters of myString and then comparing the rest to your substring. Obviously, this is not going to work in a general case, when your substring is somewhere in the middle of myString.
On each iteration try comparing not the whole myString, but rather the first substring.size() characters of it. This should fix your issue.
Here's what I have so far, but it only returns true if the string
begins with the substring.
It also fails for find("foo", "f").
To see why, add some test output to the function:
bool find(string myString, string substring)
{
std::cout << myString << ", " << substring << "\n";
// ...
}
It will print:
foo, f
oo, f
o, f
You see why this cannot work? You just keep removing the first character, until only the last character is compared with the substring to be found.
But it fails even for find("foo", "o"):
foo, o
oo, o
o, o
That's because of this line:
find(string2, substring);
You don't return the result of the recursive call.
All things considered, I think you just have the wrong algorithm here. It simply cannot work the way you have written the code.
A few other observations:
int start = 1;
int end = (int) myString.length() - 1;
That's not good style. For historical reasons, a std::string's size is unsigned, and you are using a C-style cast where static_cast should be preferred. You should just use std::string::size_type here, because it's just an internal piece of implementation code and you gain nothing from casting to int.
string string2 = myString.substr(start, end);
The second argument of substr defines the length of the substring, not the index of the last character. end sounds like you use the value as the index of the last character. Have a look at http://en.cppreference.com/w/cpp/string/basic_string/substr.

Replacing all occurrences of a substring with another substring in a long string

I'm writing a function, which takes three parameters:
target : Target String
oldVal : Old substring
newVal : New Substring (To replace the oldVal)
The task of this function is to find all the occurrence of oldVal in target string, and replace them with newVal.
This is the function I've got at the moment:
std::string replace_old_with_new(std::string target, std::string oldVal, std::string newVal) {
std::cout << "target : " << target << ", oldVal: " << oldVal << ", newVal: " << newVal << "\n";
std::string::iterator begin = target.begin();
std::string::iterator oldValBegin = oldVal.begin();
while (begin != target.end()) {
if (*begin == *oldValBegin) {
target = target.replace(begin, begin + oldVal.size(), oldVal);
begin = target.begin();
} else {
++begin;
}
}
return target;
}
The following call to the above function:
replace_old_with_new("Hello! hi hi!", "hi", "bye");
should return the string -
"Hello! bye bye!"
But, when I run the code, nothing happens. It seems like I'm stuck in an infinite loop. The cursor keeps blinking on terminal. Is something wrong with my function. I think what might be troubling is the replace call in the if block. Is that the correct way to use iterator range in the replace function call? I can do this with erase and insert. But I want to use replace here.
Strings are much smarter than you give them credit for. They know how to search, so you don't have to do it yourself.
int pos = 0;
int match_pos;
std::string result;
while ((match_pos = target.find(oldVal, pos)) != std::string::npos) {
result += target.substr(pos, match_pos - pos);
result += newVal;
pos = match_pos + target.size();
}
result += target.substr(pos, std::string::npos);
Sorry, this is a sketch; not tested, but you get the idea.

String Replace in C++

I've spent the last hour and a half trying to figure out how to run a simple search and replace on a string object in C++.
I have three string objects.
string original, search_val, replace_val;
I want to run a search command on original for the search_val and replace all occurrences with replace_val.
NB: Answers in pure C++ only. The environment is XCode on the Mac OSX Leopard.
A loop should work with find and replace
void searchAndReplace(std::string& value, std::string const& search,std::string const& replace)
{
std::string::size_type next;
for(next = value.find(search); // Try and find the first match
next != std::string::npos; // next is npos if nothing was found
next = value.find(search,next) // search for the next match starting after
// the last match that was found.
)
{
// Inside the loop. So we found a match.
value.replace(next,search.length(),replace); // Do the replacement.
next += replace.length(); // Move to just after the replace
// This is the point were we start
// the next search from.
}
}
size_t start = 0;
while(1) {
size_t where = original.find(search_val, start);
if(where==npos) {
break;
}
original.replace(where, search_val.size(), replace_val);
start = where + replace_val.size();
}
For comparison here is the function in pure C:
http://www.pixelbeat.org/libs/string_replace.c
A little bit more elegant:
void searchAndReplace(std::string& value, std::string const& search,std::string const& replace) {
for(std::string::size_type idx = value.find(search);match
idx != std::string::npos;
next = value.find(search, idx + replace.size())
)
value.replace(next, search.size(), replace);
}
#include <boost/algorithm/string.hpp>
string newstring = boost::replace_all_copy(original, search_val, replace_val);
or, if you want in-place replacement
boost::replace_all(original, search_val, replace_val);
Simple...
But limited to replaceing single char only!!
#include <algorithm>
string foo = "abc.e";
std::replace(foo.begin(), foo.end(),'.','d');
result --> foo = "abcde";
This might result in a faster execution and preserves the original if wanted.
static std::string strreplace( const std::string &original, const std::string &pattern, const std::string &newtext ) {
std::stringstream ss;
std::string::size_type last = 0;
std::string::size_type it = original.find( pattern, last );
while( it != original.npos ) {
if( it-last > 0 ) {
ss << original.substr( last, it - last );
ss << newtext;
}
last = it + pattern.size( );
it = original.find( pattern, last );
}
return ss.str( );
}
This is probably your most concentrated version of string replace:
for ( string::size_type index = 0 ;
(index = value.find(from, index)) != string::npos ;
index += to.size() )
value.replace(index, from.size(), to);
A tested code with examples.
If you want the string returned use this:
std::string ReplaceString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
If you need performance, here is an optimized function that modifies the input string, it does not create a copy of the string:
void ReplaceStringInPlace(std::string& subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
Tests:
std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;
std::cout << "ReplaceString() return value: "
<< ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not changed: "
<< input << std::endl;
ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: "
<< input << std::endl;
Output:
Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def