I'm working with c++ and XE8. Given the following code:
String __fastcall RemoveCharsFromString(String &str, const String &c)
{
for(unsigned int i=0; i<c.Length(); ++i)
{
str.Delete(std::remove(str[0], str.LastChar(), c[i]), str.LastChar());
}
}
Received errors:
Using str.Delete(remove(str[0], str.LastChar(), c[i]), str.LastChar());
results in a
Cannot convert 'int' to 'const char *'
error inside the for loop.
Using str.Delete(std::remove(str[0], str.LastChar(), c[i]), str.LastChar());
results in a
Could not find a match for 'remove(wchar_t,wchar_t*,wchar_t)'
error inside the for loop.
Searching SO and the web, it's my understanding this error is usually received when code is written with single quotes when double quotes should have been used. I don't believe that scenario is applicable in this case.
The return type of String
is Embarcadero's UnicodeString
. Details can be found here: RAD Studio VCL Reference - UnicodeString Class
In C++Builder, String
refers to System::String
, which is an alias for System::UnicodeString
in XE8.
There are a lot of mistakes in your code.
The System::String::Delete()
method expects an index and a count as input, but that is not what you are trying to pass to it. You are expecting Delete()
to work like the STL std::wstring::erase()
method, and that is simply not the case.
You are not taking into account that System::String::operator[]
is 1-based. It is not 0-based, like your code is assuming.
The System::String::LastChar()
method returns a pointer to the last UTF-16 encoded Unicode character in the string. It does not return a pointer to the string's null terminator, like your code is assuming.
You are calling the STL std::remove()
algorithm that takes a range of iterator
s as input, shifts all copies of the specified value to the end of the range, and then returns a new iterator
to where the "removed" values have been moved to within the range (so they can be erase()
'd from the container that owns the iterator
s). You cannot mix System::String::Delete()
and std::remove()
the way you are attempting to do. If you really want to use std::replace()
, you need to use it more like this instead:
String __fastcall RemoveCharsFromString(String &str, const String &c)
{
for(int i = 1; i <= c.Length(); ++i)
{
const Char *start = str.c_str();
const Char* end = start + str.Length();
Char* ptr = std::replace(start, end, c[i]);
str.Delete(1 + std::distance(start, ptr), std::distance(ptr, end));
}
}
That being said, Embarcadero's RTL has its own System::Sysutils::StringReplace()
function that you can use instead of std::replace()
:
#include <System.SysUtils.hpp>
String __fastcall RemoveCharsFromString(String &str, const String &c)
{
for(int i = 1; i <= c.Length(); ++i)
{
str = StringReplace(str, c[i], L"", TReplaceFlags() << rfReplaceAll);
}
}
Or, if you need to take UTF-16 surrogates into account in the c
string (which std::remove()
does not account for):
#include <System.SysUtils.hpp>
#include <System.Character.hpp>
String __fastcall RemoveCharsFromString(String &str, const String &c)
{
int i = 1;
while (i <= c.Length())
{
String chr;
if (IsSurrogatePair(c, i))
chr = c.SubString(i, 2);
else
chr = c.SubString(i, 1);
str = StringReplace(str, chr, L"", TReplaceFlags() << rfReplaceAll);
i += chr.Length();
}
}