Read message up to % character - c++

I have a char array:
char arr[] = "%RED**dsa0x0%xcа%wq233SSS%(dsa........";
The array must be read from the % sign to the next %. That is, the message begins with % and has an unknown length (there can be no % in the middle of the message).
Here is the code:
void SaveMessToVec(const string& str)
{
tail = tail + str;
if (tail.empty()) return;
assert(tail[0] == 0x24);
while (true)
{
size_t f = tail.find(0x24, 1);
if (f == string::npos) return;
string message = tail.substr(0, f);
//cout << message << '\n';
vecForAP.push_back(message);
tail.erase(0, f);
}
}
However, my controller can't work with string and vector. How to rewrite this code to use only char?

If you can use vector and string you can use this function.
std::vector<std::string> split(const std::string& s, char delimiter) {
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(s);
while (std::getline(tokenStream, token, delimiter)) {
if(token.size()!=0)
tokens.push_back(token);
}
return tokens;
}
int main() {
std::string str = "%RED**dsa0x0%xcа%wq233SSS%(dsa";
std::vector<std::string> vec = split(str,'%');
for(auto &v : vec)
std::cout << v << std::endl;
return 0;
}
If you cannot use string and vector you can use strtok(). strtok can tokenize a char array
int main() {
char arr[] = "%RED**dsa0x0%xcа%wq233SSS%(dsa";
char* token = strtok(arr,"%");
while(token != NULL) {
std::cout << token << std::endl;
token = strtok(NULL,"%");
}
return 0;
}
How you tried to do this is not the appropiate way to tokenize a string. But if you want to do this way I show you a solution for you.
I do not understand your whole code procisely but maybe this would be good enough for you.
vector<string> vecForAP; // global variable to store data for you
void SaveMessToVec(string& str) {
str.erase(str.begin()); //because the first letter is %
while (true){
size_t f = str.find('%');
if (f == string::npos) {
vecForAP.push_back(str);
return;
}
string message = str.substr(0,f);
vecForAP.push_back(message);
str.erase(0, f+1);
}
}

Related

Remove the words from a string that start with a certain character

I have to create a function in C++ that would remove all the words from a string that start with a certain character inputted by a user. For example, if I were to have a string "She made up her mind to meet up with him in the morning" and a substring "m", I would like my string to be "She up her to up with him in the".
I believe I would need to find the occurrences of "m", erase it and all the characters after it till the space " ". Would that be the right approach and if so what would be the best methods to use in this case?
With your kind help I have altered and added code a little bit. The first function 'GetNextWord' seems to be working alright, however, there is definitely something wrong with my function, which is supposed to strip the words, as I am not getting any output. Here is the code:
string GetNextWord(string& s, size_t pos) {
string word;
char del = ' ';
int i = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] != del) {
word += s[i];
}
else break;
}
return word;
}
string StripWordsThatBeginWithLetter(string& s, char c) {
string result;
string word;
size_t pos = 0;
while (true)
{
word = GetNextWord(s, pos);
pos += word.size() + 1;
if (word.size() == 0)
{
break;
}
if (word[0] == c) {
size_t inx = 0;
inx = s.find(word[0]);
s.erase(inx, word.length());
}
else result = s;
}
return result;
}
Here's a hint. I'm guessing this is a homework problem. And I'm probably giving too much away.
std::string GetNextWord(const std::string &s, size_t pos)
{
std::string word;
// your code goes here to return a string that includes all the chars starting from s[pos] until the start of the next word (including trailing whitespace)
// return an empty string if at the end of the string
return word;
}
std::string StripWordsThatBeginWithLetter(const std::string& s, char c)
{
std::string result;
std::string word;
size_t pos = 0;
while (true)
{
word = GetNextWord(s, pos);
pos += word.size();
if (word.size() == 0)
{
break;
}
// your code on processing "word" goes here with respect
// to "c" goes here
}
return result;
}
Simple example in french. You are a gentleman and dont want to say "merde" too often, and so decided not to say any word starting with 'm'.
This program will help you :
"je suis beau merde je sais" becomes "je suis beau je sais"
#include <string>
#include <algorithm>
int main(){
std::string str ("je suis beau merde je le sais");
const auto forbiden_start ((const char) 'm');
std::cout << "initial rude string (word starting with \'" << forbiden_start << "\') : " << str << std::endl;
auto i (str.begin ());
auto wait (false);
std::for_each (str.begin (), str.end (), [&i, &forbiden_start, &wait] (const auto& c) {
if (wait) {
if (c == ' ') {
wait = false; return;
}
}
else {
if (c == forbiden_start) {
wait = true;
}
else *i++ = c;
}
});
if (i != str.end ()) str.erase (i, str.end ());
std::cout << "polite string : " << str << std::endl;
return 0;
}
All is not tested (separator is " "), but it is the idea

Complex algorithm to extract numbers/number range from a string

I am working on a algorithm where I am trying the following output:
Given values/Inputs:
char *Var = "1-5,10,12,15-16,25-35,67,69,99-105";
int size = 29;
Here "1-5" depicts a range value, i.e. it will be understood as "1,2,3,4,5" while the values with just "," are individual values.
I was writing an algorithm where end output should be such that it will give complete range of output as:
int list[]=1,2,3,4,5,10,12,15,16,25,26,27,28,29,30,31,32,33,34,35,67,69,99,100,101,102,103,104,105;
If anyone is familiar with this issue then the help would be really appreciated.
Thanks in advance!
My initial code approach was as:
if(NULL != strchr((char *)grp_range, '-'))
{
int_u8 delims[] = "-";
result = (int_u8 *)strtok((char *)grp_range, (char *)delims);
if(NULL != result)
{
start_index = strtol((char*)result, (char **)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
while(NULL != result)
{
end_index = strtol((char*)result, (char**)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
while(start_index <= end_index)
{
grp_list[i++] = start_index;
start_index++;
}
}
else if(NULL != strchr((char *)grp_range, ','))
{
int_u8 delims[] = ",";
result = (unison_u8 *)strtok((char *)grp_range, (char *)delims);
while(result != NULL)
{
grp_list[i++] = strtol((char*)result, (char**)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
}
But it only works if I have either "0-5" or "0,10,15". I am looking forward to make it more versatile.
Here is a C++ solution for you to study.
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int ConvertString2Int(const string& str)
{
stringstream ss(str);
int x;
if (! (ss >> x))
{
cerr << "Error converting " << str << " to integer" << endl;
abort();
}
return x;
}
vector<string> SplitStringToArray(const string& str, char splitter)
{
vector<string> tokens;
stringstream ss(str);
string temp;
while (getline(ss, temp, splitter)) // split into new "lines" based on character
{
tokens.push_back(temp);
}
return tokens;
}
vector<int> ParseData(const string& data)
{
vector<string> tokens = SplitStringToArray(data, ',');
vector<int> result;
for (vector<string>::const_iterator it = tokens.begin(), end_it = tokens.end(); it != end_it; ++it)
{
const string& token = *it;
vector<string> range = SplitStringToArray(token, '-');
if (range.size() == 1)
{
result.push_back(ConvertString2Int(range[0]));
}
else if (range.size() == 2)
{
int start = ConvertString2Int(range[0]);
int stop = ConvertString2Int(range[1]);
for (int i = start; i <= stop; i++)
{
result.push_back(i);
}
}
else
{
cerr << "Error parsing token " << token << endl;
abort();
}
}
return result;
}
int main()
{
vector<int> result = ParseData("1-5,10,12,15-16,25-35,67,69,99-105");
for (vector<int>::const_iterator it = result.begin(), end_it = result.end(); it != end_it; ++it)
{
cout << *it << " ";
}
cout << endl;
}
Live example
http://ideone.com/2W99Tt
This is my boost approach :
This won't give you array of ints, instead a vector of ints
Algorithm used: (nothing new)
Split string using ,
Split the individual string using -
Make a range low and high
Push it into vector with help of this range
Code:-
#include<iostream>
#include<vector>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
int main(){
std::string line("1-5,10,12,15-16,25-35,67,69,99-105");
std::vector<std::string> strs,r;
std::vector<int> v;
int low,high,i;
boost::split(strs,line,boost::is_any_of(","));
for (auto it:strs)
{
boost::split(r,it,boost::is_any_of("-"));
auto x = r.begin();
low = high =boost::lexical_cast<int>(r[0]);
x++;
if(x!=r.end())
high = boost::lexical_cast<int>(r[1]);
for(i=low;i<=high;++i)
v.push_back(i);
}
for(auto x:v)
std::cout<<x<<" ";
return 0;
}
You're issue seems to be misunderstanding how strtok works. Have a look at this.
#include <string.h>
#include <stdio.h>
int main()
{
int i, j;
char delims[] = " ,";
char str[] = "1-5,6,7";
char *tok;
char tmp[256];
int rstart, rend;
tok = strtok(str, delims);
while(tok != NULL) {
for(i = 0; i < strlen(tok); ++i) {
//// range
if(i != 0 && tok[i] == '-') {
strncpy(tmp, tok, i);
rstart = atoi(tmp);
strcpy(tmp, tok + i + 1);
rend = atoi(tmp);
for(j = rstart; j <= rend; ++j)
printf("%d\n", j);
i = strlen(tok) + 1;
}
else if(strchr(tok, '-') == NULL)
printf("%s\n", tok);
}
tok = strtok(NULL, delims);
}
return 0;
}
Don't search. Just go through the text one character at a time. As long as you're seeing digits, accumulate them into a value. If the digits are followed by a - then you're looking at a range, and need to parse the next set of digits to get the upper bound of the range and put all the values into your list. If the value is not followed by a - then you've got a single value; put it into your list.
Stop and think about it: what you actually have is a comma
separated list of ranges, where a range can be either a single
number, or a pair of numbers separated by a '-'. So you
probably want to loop over the ranges, using recursive descent
for the parsing. (This sort of thing is best handled by an
istream, so that's what I'll use.)
std::vector<int> results;
std::istringstream parser( std::string( var ) );
processRange( results, parser );
while ( isSeparator( parser, ',' ) ) {
processRange( results, parser );
}
with:
bool
isSeparator( std::istream& source, char separ )
{
char next;
source >> next;
if ( source && next != separ ) {
source.putback( next );
}
return source && next == separ;
}
and
void
processRange( std::vector<int>& results, std::istream& source )
{
int first = 0;
source >> first;
int last = first;
if ( isSeparator( source, '-' ) ) {
source >> last;
}
if ( last < first ) {
source.setstate( std::ios_base::failbit );
}
if ( source ) {
while ( first != last ) {
results.push_back( first );
++ first;
}
results.push_back( first );
}
}
The isSeparator function will, in fact, probably be useful in
other projects in the future, and should be kept in your
toolbox.
First divide whole string into numbers and ranges (using strtok() with "," delimiter), save strings in array, then, search through array looking for "-", if it present than use sscanf() with "%d-%d" format, else use sscanf with single "%d" format.
Function usage is easily googling.
One approach:
You need a parser that identifies 3 kinds of tokens: ',', '-', and numbers. That raises the level of abstraction so that you are operating at a level above characters.
Then you can parse your token stream to create a list of ranges and constants.
Then you can parse that list to convert the ranges into constants.
Some code that does part of the job:
#include <stdio.h>
// Prints a comma after the last digit. You will need to fix that up.
void print(int a, int b) {
for (int i = a; i <= b; ++i) {
printf("%d, ", i);
}
}
int main() {
enum { DASH, COMMA, NUMBER };
struct token {
int type;
int value;
};
// Sample input stream. Notice the sentinel comma at the end.
// 1-5,10,
struct token tokStream[] = {
{ NUMBER, 1 },
{ DASH, 0 },
{ NUMBER, 5 },
{ COMMA, 0 },
{ NUMBER, 10 },
{ COMMA, 0 } };
// This parser assumes well formed input. You have to add all the error
// checking yourself.
size_t i = 0;
while (i < sizeof(tokStream)/sizeof(struct token)) {
if (tokStream[i+1].type == COMMA) {
print(tokStream[i].value, tokStream[i].value);
i += 2; // skip to next number
}
else { // DASH
print(tokStream[i].value, tokStream[i+2].value);
i += 4; // skip to next number
}
}
return 0;
}

Splitting a string with delimiter in C++

There are a few examples about this question. However most of the answers are not what I am looking for.
I am looking for a way to implement an efficient and easy function rather than using boost or any other non STL libraries. If you ask me why, in most coding competitions and interviews, you are not allowed to use them.
Here is the closest that I can approach:
vector<string> SplitString(const char *str, char c)
{
vector<string> result;
do {
const char *begin = str;
while(*str != c && *str) {
str++;
}
result.push_back(string(begin, str));
} while (0 != *str++);
return result;
}
int main() {
string mainString = "This is a sentence. Another sentence. The third sentence. This is the last sentence.";
vector<string> sentences;
sentences = SplitString(mainString.c_str(), '.');
while (!sentences.empty()) {
cout << sentences.back() << endl;
sentences.pop_back();
}
return 0;
}
Now the problem with this is, it can only have a char delimiter not string. I have thought of implementing a few ways but they seemed way too complex. The easiest one that I thought was, convert delimiter to char array use c as the first char of the delimiter char array after this:
while(*str != c && *str) {
str++;
}
const char *beginDelim = *cArr;
while(1) {
if (*str == *cArr && *str && *cArr) {
str++;
cArr++;
}
else if (!*cArr) {
break;
}
else if (*cArr) {
cArr = beginDelim;
}
}
And the code continues from result.push_back() part.
So I was wondering if are there any way to implement an efficient and easy function for splitting a string with a string delimiter?
Generally speaking, a string is a char pointer. So you should search for the first character in the delimeter, then check the very next character. Also in looking at your code I am not sure that while (0 != *str++) is doing what you think it is. I think you mean for it to be null terminated.
something like this should do it:
vector<string> SplitString(const char* str,const char* d) {
vector<string> result;
size_t len = strlen(d);
const char* start = str;
while ( str = strstr(start,d) ) {
result.push_back(string(start,len));
start = str + len;
}
result.push_back(start);
return result;
}
How's this:
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
vector<string> SplitString(const string &str, const string &delim)
{
vector<string> ret;
string::const_iterator prev = str.begin();
for (string::const_iterator i = str.begin(); i < str.end() - delim.length()+1; ++i)
{
if (equal(delim.begin(), delim.end(), i)) {
ret.push_back(string(prev,i));
i += delim.length()-1;
prev = i+1;
}
}
ret.push_back(string(prev,str.end()));
return ret;
}
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> SplitString(string str, const string &delim) {
vector<string> result;
size_t found;
while((found = str.find(delim)) != string::npos) {
result.push_back(str.substr(0, found));
str = str.substr(found + delim.size());
}
return result;
}
int main() {
string mainString = "This is a sentence. Another sentence. The third sentence. This is the last sentence.";
vector<string> sentences;
sentences = SplitString(mainString, ".");
for(auto& sentence : sentences) {
cout << sentence << endl;
}
return 0;
}
vector<string>split(string str, const char d){
string temp;
vector<string>vct;
for(int i = 0; str[i] != '\0'; i++){
if(str[i] != d){
temp += str[i];
}else if(!empty(temp)){
vct.push_back(temp), temp.clear();
}
}
vct.push_back(temp);
return vct;
}
Takes two arguments
const char d as delimiter.
string str as string to be splitted.
stores splitted string in a vector and returns it.
Although, I'm not sure about efficiency of this code. :)

c++: I am trying to reverse the order of words in string (not the whole string)

#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;
}
}

How to find and replace string?

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;