Reputation: 2649
What is an efficient way to shift the text within a std::string, starting at some offset, to the left by X amount of characters?
Example:
(Some sTring here)
Shifted to the left by 1, starting at T, would yield:
(Some Tring here)
Background Info
In a compiler for a text pattern language, in which text of the form:
(some expression here)
represent expressions to be replaced with some value. Those expressions can appear interspersed with text; something like the following:
There are ($count) types of things.
The above would be replaced with something like the following, after the text is evaluated by the compiler.
There are 42 types of things.
Now, I want support the ability to 'escape' expressions, so that text that would normally represent expressions can be written verbatim. So this:
There are \($count) types of things.
would be outputted like this:
There are ($count) types of things.
Basically, all that needs to happen is for the text after There are to be moved by 1 byte to the left. I was trying to think of an efficient way to do this. I wish I could memmove std::string's data buffer from '(...' by 1 byte to the left, but I'm not sure if that's possible.
I hate the idea of copying a big chunk of a string just to move the contents to the left by 1 character.
So, I'm hoping there is a better way than to do something like this:
auto size = buffer.size()
auto temp = buffer.substr(parentPosistion, size - parentPosistion)
buffer.assign(temp, parentPosistion - 1)
buffer.resize(size - 1)
Upvotes: 1
Views: 1820
Reputation: 12058
The best way to do this is to use string::erase to remove slash and then proceed with further operations. erase
internally should be an efficient memmove
, since string
's data is stored in continuous block of memory.
Example:
string s = "There are \\{$count} types of things.";
cout << s << endl;
size_t slash_pos = s.find("\\");
if(slash_pos != string::npos)
s.erase(slash_pos, 1);
cout << s << endl;
Output:
There are \{$count} types of things.
There are {$count} types of things.
You did not specified the amount of input data, but yes - this approach can be slow for large strings, containing multiple slashes.
In such case, you would want to remove all slashes in single run. It is possible with std::remove:
string s = "\\{$count1} \\{$count2} \\{$count3}";
cout << s << endl;
s.erase(std::remove(s.begin(), s.end(), '\\'), s.end());
cout << s << endl;
Output:
\{$count1} \{$count2} \{$count3}
{$count1} {$count2} {$count3}
Explanation: std::remove(b, e, v)
transforms range [b; e) by removing all elements with value equal to v
and returns iterator to end of new sequence. Then, we use this iterator to remove redundant characters. For example, if you simply called:
std::remove(s.begin(), s.end(), '\\');
Second output would be:
{$count1} {$count2} {$count3}t3}
Upvotes: 2
Reputation: 56547
Here is a way using std::rotate
, will shift left at some offset
by an arbitrary amount X
, reducing the length of the string by X
#include <algorithm>
#include <iostream>
#include <string>
void shift_left(std::string& str, std::size_t offset, std::size_t X)
{
std::rotate(std::next(str.begin(), offset),
std::next(str.begin(), offset + X),
str.end() );
str = str.substr(0, str.size() - X);
}
int main()
{
std::string str = "Some sTring here";
shift_left(str, 5, 2); // Outputs: Some ring here
std::cout << str << std::endl;
}
Upvotes: 1
Reputation: 21146
If you want to remove e.g. all back slashes, then the shortest solution I can think of is this:
#include <algorithm>
#include <string>
#include <iostream>
int main()
{
std::string str = "There are \\{$count} types of things.";
str.erase(std::remove(str.begin(), str.end(), '\\'),str.end());
std::cout << str << std::endl;
}
And I doubt there is a more efficient solution. If you want to remove multiple different characters in one go, you can use remove_if.
Upvotes: 0