I want to replace substring within a string,
For eg: the string is aa0_aa1_bb3_c*a0_a,
so I want to replace the substring a0_a with b1_a, but I dont want aa0_a to get replaced.
Basically, no alphabet should be present before and after the substring "a0_a" (to be replaced).
That's what regexes are good at. It exists in standard library since C++11, if you have an older version, you can also use Boost.
With the standard library version, you could do (ref):
std::string result;
std::regex rx("([^A-Za-Z])a0_a[^A-Za-Z])");
result = std::regex_replace("aa0_aa1_bb3_c*a0_a", rx, "$1b1_a$2");
(beware: untested)
Easy enough to do if you loop through each character. Some pseudocode:
string toReplace = "a0_a";
for (int i = 0; i < myString.length; i++) {
//filter out strings starting with another alphabetical char
if (!isAlphabet(myString.charAt(i))) {
//start the substring one char after the char we have verified to be not alphabetical
if (substring(myString(i + 1, toReplace.length)).equals(toReplace)) {
//make the replacement here
}
}
}
Note that you will need to check for indexing out of bounds when looking at the substrings.
Related
I have already checked topics similar to this one but no one has been able to solve this problem.
So, I have to look for a character inside a string but it doesn't seem to work.
if (tracciatonuovos.find('T'))
{
nterminale++;
}
The counter does not increase. But if I try to find an empty space, it counts for me, and yet the string is full
First value is string, second is length of string, and third is the value of counter "nterminale".
use the find function from the std::string class
std::string mystr = "Some String with T";
size_t apos = mystr.find("T");
Read more about it here
If you want to find the first occurrence use :
find_first_of
And if you want to repeatedly find all occurrences of a specific character you will also need to specify a search start position and will need to write a loop say something like :
size_t pos = 0;
while((pos = mystr.find(whatever, pos)) != std::string::npos)
{
pos +=1;
// and your other logic here
}
How can i replace multiple occurrences of a character with a string containing the occurrence number.
e.g if i have the following expression.
insert into emp values(?,?,?)
I want the following converted string.
insert into emp values(_p_1,_p_2,_p_3)
I am trying this using the boost regular expression.
Can anyone tell me how to achieve this using the boost c++ (with no or minimum iteration).
currently I am using the following approach:
std::wstring q=L"insert into emp values(?,?,?)";
auto loc = q.find(L"?");
auto len = wcslen(L"?");
auto c=1;
while(loc != std::wstring::npos)
{
q.replace(loc, len , L"_p_"+to_wstring(c));
c++;
loc = q.find(L"?");
}
cout<<q.c_str();
Please suggest better and efficient approaches.
I'd just forget regular expressions and trying to do this simple thing with Boost.
It's like asking, "how do I add 1 to a variable using Boost regular expressions"?
Best answer, IMHO, is to instead just use ++ for the task of adding 1, and to use a loop to replace special characters with strings.
string const query_format = "insert into emp values(?,?,?)";
string const params[] = {"_p_1", "_p_2", "_p3"};
string query;
string const* p = params;
for( char const c : query_format )
{
if( c == '?' ) { query += *p++; } else { query += c; }
}
// Use `query`
One might choose to wrap this up as a replace function.
Disclaimer: code not touched by compiler.
If you control the query_format string, why not instead make the placeholders compatible with Boost format.
Re the parenthetical requirement
” with no or minimum iteration
there's iteration involved no matter how you do this. You can hide the iteration behind a function name, but that's all. It's logically impossible to actually avoid the iteration, and it's trivial (completely trivial) to hide it behind a function name.
I have a list of data I need to parse that contains a name and phone number in a text file. The name and phone number must be split into different string vars, but I can't really think of a fast method to do so. I can easily run a for loop and do something like
//file line read into string `line`
string name;
string number;
for(int i = 0; i < line.length(); i++) {
if(isDigit(line[i])) {
name = line.substr(0, i-1);
number = line.substr(i, line.length()-i);
}
}
but I feel there has to be an easy way to do this in C++.
You could use find_first_of to find the first digit without using a loop:
string s("hello12345");
size_t i = s.find_first_of("0123456789");
string name(s.substr(0, i));
string number(s.substr(i));
Demo.
Note that if you wish to take a substring to the end of the original string, you do not need to pass the length: the library will figure it out automatically for you.
I'm making a function that removes elements from a string. However, I cant seem to get both of my loops to work together. The first while loop works flawlessly. I looked into it and I believe it might be because when "find_last_of" isn't found, it still returns a value (which is throwing off my loop). I haven't been able to figure out how I can fix it. Thank you.
#include <iostream>
#include <string>
using namespace std;
string foo(string word) {
string compare = "!##$";
string alphabet = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
while(word.find_first_of(compare) < word.find_first_of(alphabet)) {
int position = word.find_first_of(compare);
word = word.substr(++position);
}
while(word.find_last_of(compare) > word.find_last_of(alphabet)){
int size = word.length();
word = word.substr(0, --size);
}
return word;
}
int main() {
cout << foo("!!hi!!");
return 0;
}
I wrote it like this so compound words would not be affected. Desired result: "hi"
It's not entirely clear what you're trying to do, but how about replacing the second loop with this:
string::size_type p = word.find_last_not_of(compare);
if(p != string::npos)
word = word.substr(0, ++p);
It's not clear if you just want to trim certain characters from the front and back of word or if you want to remove every one of a certain set of characters from word no matter where they are. Based on the first sentence of your question, I'll assume you want to do the latter: remove all characters in compare from word.
A better strategy would be to more directly examine each character to see if it needs to be removed, and if so, do so, all in one pass through word. Since compare is quite short, something like this is probably good enough:
// Rewrite word by removing all characters in compare (and then erasing the
// leftover space, if any, at the end). See std::remove_if() docs.
word.erase(std::remove_if(word.begin(),
word.end(),
// Returns true if a character is to be removed.
[&](const char ch) {
return compare.find(ch) != compare.npos;
}),
word.end());
BTW, I'm not sure why there is both a compare and alphabet string in your example. It seems you would only need to define one or the other, and not both. A character is either one to keep or one to remove.
I have an XML string that i wish to log out. this XML contains some sensitive data that i'd like to mask out before sending to the log file. Currently using std::regex to do this:
std::regex reg("<SensitiveData>(\\d*)</SensitiveData>");
return std::regex_replace(xml, reg, "<SensitiveData>......</SensitiveData>");
Currently the data is being replaced by exactly 6 '.' characters, however what i really want to do is to replace the sensitive data with the correct number of dots. I.e. I'd like to get the length of the capture group and put that exact number of dots down.
Can this be done?
regex_replace of C++11 regular expressions does not have the capability you are asking for — the replacement format argument must be a string. Some regular expression APIs allow replacement to be a function that receives a match, and which could perform exactly the substitution you need.
But regexps are not the only way to solve a problem, and in C++ it's not exactly hard to look for two fixed strings and replace characters inbetween:
const char* const PREFIX = "<SensitiveData>";
const char* const SUFFIX = "</SensitiveData>";
void replace_sensitive(std::string& xml) {
size_t start = 0;
while (true) {
size_t pref, suff;
if ((pref = xml.find(PREFIX, start)) == std::string::npos)
break;
if ((suff = xml.find(SUFFIX, pref + strlen(PREFIX))) == std::string::npos)
break;
// replace stuff between prefix and suffix with '.'
for (size_t i = pref + strlen(PREFIX); i < suff; i++)
xml[i] = '.';
start = suff + strlen(SUFFIX);
}
}