Related
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.
for example we have in our set:
bin/obj/Debug/CloudServerPrototype/ra.write.1.tlog
bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog
bin/obj/Debug/vc100.idb
bin/obj/Debug/vc100.pdb
So this is what I tried based on this grate answer:
#include <iostream>
#include <algorithm>
#include <set>
#include <string>
#include <iterator>
using namespace std;
struct get_pertinent_part
{
const std::string given_string;
get_pertinent_part(const std::string& s)
:given_string(s)
{
}
std::string operator()(const std::string& s)
{
std::string::size_type first = 0;
if (s.find(given_string) == 0)
{
first = given_string.length() + 1;
}
std::string::size_type count = std::string::npos;
std::string::size_type pos = s.find_last_of("/");
if (pos != std::string::npos && pos > first)
{
count = pos + 1 - first;
}
return s.substr(first, count);
}
};
void directory_listning_without_directories_demo()
{
set<string> output;
set<string> demo_set;
demo_set.insert("file1");
demo_set.insert("file2");
demo_set.insert("folder/file1");
demo_set.insert("folder/file2");
demo_set.insert("folder/folder/file1");
demo_set.insert("folder/folder/file2");
demo_set.insert("bin/obj/Debug/CloudServerPrototype/ra.write.1.tlog");
demo_set.insert("bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog");
demo_set.insert("bin/obj/Debug/vc100.idb");
demo_set.insert("bin/obj/Debug/vc100.pdb");
std::transform(demo_set.begin(),
demo_set.end(),
std::inserter(output, output.end()),
get_pertinent_part("bin/obj/Debug/"));
std::copy(output.begin(),
output.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
int main()
{
directory_listning_without_directories_demo();
cin.get();
return 0;
}
This outputs:
CloudServerPrototype/
file1
file2
folder/
folder/folder/
vc100.idb
vc100.pdb
and we are given with bin/obj/Debug/string. We want to cout:
vc100.idb
vc100.pdb
CloudServerPrototype/
How to do such thing?
Quick example of what you want to do.
String.find(): http://www.cplusplus.com/reference/string/string/find/
String.subStr(): http://www.cplusplus.com/reference/string/string/substr/
string str = "bin/obj/Debug/vc100.pdb";
string checkString ("bin/obj/Debug");
// Check if string starts with the check string
if (str.find(checkString) == 0){
// Check if last letter if a "/"
if(str.substr(str.length()-1,1) == "/"){
// Output strating at the end of the check string and for
// the differnce in the strings.
cout << str.substr(checkString.length(), (str.length() - checkString.length()) ) << endl;
}
}
It's not clear with which part of the problem you are stuck, so here is a starter for you.
To get the parts of the strings between "given string" and the final '/' (where present):
std::string get_pertinent_part(const std::string& s)
{
std::string::size_type first = 0;
if (s.find(given_string) == 0)
{
first = given_string.length() + 1;
}
std::string::size_type count = std::string::npos;
std::string::size_type pos = s.find_last_of("/");
if (pos != std::string::npos && pos > first)
{
count = pos + 1 - first;
}
return s.substr(first, count);
}
To insert these parts into a new set (output) to guarantee uniqueness you can use the following:
std::transform(your_set.begin(),
your_set.end(),
std::inserter(output, output.end()),
get_pertinent_part);
You may wish to pass given_string into get_pertinent_part(), in which case you'll need to convert it to a functor:
struct get_pertinent_part
{
const std::string given_string;
get_pertinent_part(const std::string& s)
:given_string(s)
{
}
std::string operator()(const std::string& s)
{
std::string::size_type first = 0;
//
// ...same code as before...
//
return s.substr(first, count);
}
};
You can then call it this way:
std::transform(your_set.begin(),
your_set.end(),
std::inserter(output, output.end()),
get_pertinent_part("bin/obj/Debug"));
To output the new set:
std::copy(output.begin(),
output.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
Sorting the results is left as an exercise.
The easiest way I can think of, using the standard C functions, would be:
char * string1 = "bin/obj/Debug"
char * string2 = "bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog"
char result[64];
// the above code is just to bring the strings into this example
char * position = strstr(string1, string2);
int substringLength;
if(position != NULL){
position += strlen(string2);
substringLength = strchr(position, '/') - position;
strncpy(result, position, substringLength);
}else{
strcpy(result, string1); // this case is for when your first string is not found
}
cout << result;
The first thing that occurs, is finding the substring, string1, in the string we are analyzing, being string2. Once we found the starting point, and assuming it was there at all, we add the length of that substring to that starting point using pointer arithmatic, and then find the resulting string's length by subtracting the starting position from the ending position, which is found with strchr(position, '/'). Then we simply copy that substring into a buffer and it's there to print with cout.
I am sure there is a fancy way of doing this with std::string, but I'll leave that to anyone who can better explain c++ strings, I never did manage to get comfortable with them, haha
#include <iostream>
#include <vector>
using namespace std;
void RevStr (char *str)
{
if(*str !=0)
{
vector<char> v1;
while((*str != ' ')&&(*str !=0))
v1.push_back(*str++);
// trying to not add space in the last word of string
if(*str !=0)
{
v1.push_back(' ');
str++;
}
RevStr(str);
cout<<*str;
}
}
int main()
{
RevStr("hello world!");
cout<<endl;
}
I want to change the order of words in the string for example " how are you" => "you are how"
I am having some problem, its not printing correctly (print only w), please help me and tell me what i did wrong. However i know that I should not call "cout<<*str;
" since i am inserting the "array of char" in stack (recurssion) but i dont know what i need to do.
C++ makes it simple:
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
std::string reverse(std::string const& text)
{
std::stringstream inStream(text);
std::stringstream outStream;
std::vector<std::string> words;
std::copy(std::istream_iterator<std::string>(inStream), std::istream_iterator<std::string>(), std::back_inserter(words));
std::copy(words.rbegin(), words.rend(), std::ostream_iterator<std::string>(outStream, " "));
return outStream.str();
}
int main()
{
std::cout << reverse("Hello World") << "\n";
}
A common approach to do this is to reverse the entire string first, then for each word, reverse the letters in the word. So no recursion is necessary. You might find it easier to give this a try (yes, I know this isn't exactly an answer to your question :) ).
Use cout << str, not cout << *str to print a string. There's an operator<< overload for char *. But maybe that's not what you're trying to do; I can't quite follow your logic, in any event.
You're losing the "hello" part.
The algorithm you seem to go for does this:
each call to RevStr isolates the first word in the string it is passed as a parameter
calls RevStr with the remaining of the string
prints the word it isolated at step 1 as the stack unwinds
Basically, you should be printing the v1 data.
I would strongly advise making using some of the functionality exposed via std::string as a place to start.
One way you might do this would look like this:
std::string ReverseString(std::string s)
{
std::stack<std::string > stack;
std::string tmpstr = "";
std::string newstr = "";
size_t strsize = s.size();
size_t pos = 0; size_t tmppos = 0;
size_t i = 0; size_t stacksize = 0;
while( pos < strsize )
{
tmppos = s.find(" ", pos, 1); // starting as pos, look for " "
if (tmppos == std::string::npos) // std::string::npos => reached end
{
tmppos = strsize; // don't forget the last item.
}
tmpstr = s.substr(pos, tmppos-pos); // split the string.
stack.push(tmpstr); // push said string onto the stack
pos = tmppos+1;
}
stacksize = stack.size();
for ( i = 0; i < stacksize; i++ )
{
tmpstr = stack.top(); // grab string from top of the stack
stack.pop(); // stacks being LIFO, we're getting
if ( i != 0 ) // everything backwards.
{
newstr.append(" "); // add preceding whitespace.
}
newstr.append(tmpstr); // append word.
}
return newstr;
}
It's by no means the best or fastest way to achieve this; there are many other ways you could do it (Jerry Coffin mentions using std::vector with an iterator, for example), but as you have the power of C++ there, to me it would make sense to use it.
I've done it this way so you could use a different delimiter if you wanted to.
In case you're interested, you can now use this with:
int main(int argc, char** argv)
{
std::string s = "In Soviet Russia String Format You";
std::string t = ReverseString(s);
std::cout << t << std::endl;
}
given that its a char*, this reverses it inplace (ie, doesn't require more memory proportional to the incoming 'str'). This avoids converting it to a std::string ( not that its a bad idea to, just because it's a char* to start with.)
void reverse_words(char* str)
{
char* last = strlen(str) + str;
char *s, *e;
std::reverse(str,last);
for(s=e=str; e != last; e++)
{
if(*e == ' ')
{
std::reverse(s,e);
s = e+1;
}
}
std::reverse(s,e);
}
void Reverse(const string& text)
{
list<string> words;
string temp;
for ( auto cur = text.begin(); cur != text.end(); ++cur)
{
if (*cur == ' ')
{
words.push_front(temp);
temp.clear();
}
else
{
temp += *cur;
}
}
if (! temp.empty())
{
words.push_front(temp);
}
for_each(words.begin(), words.end(), [](const string& word) { cout << word << " "; });
cout << endl;
}
void swap(char* c1, char* c2) {
char tmp = *c1;
*c1 = *c2;
*c2 = tmp;
}
void reverse(char* s, char* e) {
if (s == NULL || e == NULL)
return;
while(s < e)
swap(s++, e--);
}
void reverse_words(char* line) {
if (line == NULL)
return;
reverse(line, line+strlen(line)-1);
char *s = line;
char *e;
while (*s != '\0') {
e = s;
while (*e != ' ' && *e != '\0') ++e;
--e;
reverse(s,e);
s = e+2;
}
}
If s is a std::string, then is there a function like the following?
s.replace("text to replace", "new text");
Replace first match
Use a combination of std::string::find and std::string::replace.
Find the first match:
std::string s;
std::string toReplace("text to replace");
size_t pos = s.find(toReplace);
Replace the first match:
s.replace(pos, toReplace.length(), "new text");
A simple function for your convenience:
void replace_first(
std::string& s,
std::string const& toReplace,
std::string const& replaceWith
) {
std::size_t pos = s.find(toReplace);
if (pos == std::string::npos) return;
s.replace(pos, toReplace.length(), replaceWith);
}
Usage:
replace_first(s, "text to replace", "new text");
Demo.
Replace all matches
Define this O(n) method using std::string as a buffer:
void replace_all(
std::string& s,
std::string const& toReplace,
std::string const& replaceWith
) {
std::string buf;
std::size_t pos = 0;
std::size_t prevPos;
// Reserves rough estimate of final size of string.
buf.reserve(s.size());
while (true) {
prevPos = pos;
pos = s.find(toReplace, pos);
if (pos == std::string::npos)
break;
buf.append(s, prevPos, pos - prevPos);
buf += replaceWith;
pos += toReplace.size();
}
buf.append(s, prevPos, s.size() - prevPos);
s.swap(buf);
}
Usage:
replace_all(s, "text to replace", "new text");
Demo.
Boost
Alternatively, use boost::algorithm::replace_all:
#include <boost/algorithm/string.hpp>
using boost::replace_all;
Usage:
replace_all(s, "text to replace", "new text");
Do we really need a Boost library for seemingly such a simple task?
To replace all occurences of a substring use this function:
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 modified: "
<< 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
Yes: replace_all is one of the boost string algorithms:
Although it's not a standard library, it has a few things on the standard library:
More natural notation based on ranges rather than iterator pairs. This is nice because you can nest string manipulations (e.g., replace_all nested inside a trim). That's a bit more involved for the standard library functions.
Completeness. This isn't hard to be 'better' at; the standard library is fairly spartan. For example, the boost string algorithms give you explicit control over how string manipulations are performed (i.e., in place or through a copy).
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str("one three two four");
string str2("three");
str.replace(str.find(str2),str2.length(),"five");
cout << str << endl;
return 0;
}
Output
one five two four
like some say boost::replace_all
here a dummy example:
#include <boost/algorithm/string/replace.hpp>
std::string path("file.gz");
boost::replace_all(path, ".gz", ".zip");
Not exactly that, but std::string has many replace overloaded functions.
Go through this link to see explanation of each, with examples as to how they're used.
Also, there are several versions of string::find functions (listed below) which you can use in conjunction with string::replace.
find
rfind
find_first_of
find_last_of
find_first_not_of
find_last_not_of
Also, note that there are several versions of replace functions available from <algorithm> which you can also use (instead of string::replace):
replace
replace_if
replace_copy
replace_copy_if
// replaced text will be in buffer.
void Replace(char* buffer, const char* source, const char* oldStr, const char* newStr)
{
if(buffer==NULL || source == NULL || oldStr == NULL || newStr == NULL) return;
int slen = strlen(source);
int olen = strlen(oldStr);
int nlen = strlen(newStr);
if(olen>slen) return;
int ix=0;
for(int i=0;i<slen;i++)
{
if(oldStr[0] == source[i])
{
bool found = true;
for(int j=1;j<olen;j++)
{
if(source[i+j]!=oldStr[j])
{
found = false;
break;
}
}
if(found)
{
for(int j=0;j<nlen;j++)
buffer[ix++] = newStr[j];
i+=(olen-1);
}
else
{
buffer[ix++] = source[i];
}
}
else
{
buffer[ix++] = source[i];
}
}
}
Here's the version I ended up writing that replaces all instances of the target string in a given string. Works on any string type.
template <typename T, typename U>
T &replace (
T &str,
const U &from,
const U &to)
{
size_t pos;
size_t offset = 0;
const size_t increment = to.size();
while ((pos = str.find(from, offset)) != T::npos)
{
str.replace(pos, from.size(), to);
offset = pos + increment;
}
return str;
}
Example:
auto foo = "this is a test"s;
replace(foo, "is"s, "wis"s);
cout << foo;
Output:
thwis wis a test
Note that even if the search string appears in the replacement string, this works correctly.
void replace(char *str, char *strFnd, char *strRep)
{
for (int i = 0; i < strlen(str); i++)
{
int npos = -1, j, k;
if (str[i] == strFnd[0])
{
for (j = 1, k = i+1; j < strlen(strFnd); j++)
if (str[k++] != strFnd[j])
break;
npos = i;
}
if (npos != -1)
for (j = 0, k = npos; j < strlen(strRep); j++)
str[k++] = strRep[j];
}
}
int main()
{
char pst1[] = "There is a wrong message";
char pfnd[] = "wrong";
char prep[] = "right";
cout << "\nintial:" << pst1;
replace(pst1, pfnd, prep);
cout << "\nfinal : " << pst1;
return 0;
}
void replaceAll(std::string & data, const std::string &toSearch, const 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());
}
}
More CPP utilities: https://github.com/Heyshubham/CPP-Utitlities/blob/master/src/MEString.cpp#L60
is there a function like the following?
One other(in addition to using boost and other methods given in different answers) possible way of doing this is using std::regex_replace as shown below:
std::string s{"my name is my name and not my name mysometext myto"}; //this is the original line
std::string replaceThis = "my";
std::string replaceWith = "your";
std::regex pattern("\\b" + replaceThis + "\\b");
std::string replacedLine = std::regex_replace(s, pattern, replaceWith);
std::cout<<replacedLine<<std::endl;
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