One possible solution is processing the string in reverse.
So starting from the end of the string, if string element i == c and element i - 1 == c, then erase element i.
std::string squeeze(const std::string& s, char c)
std::string str = s;
size_t len = str.length();
// process the string from end to start
for (size_t i = len - 1; i > 0; --i)
if (str[i] == c && str[i - 1] == c)
str.erase(str.begin() + i);
The first thing I will point out is that if you need a local copy of the string, then you should take that string by value (instead of const-reference), it is preferrable in general to do so, and it also leads to simpler code.
Then, you have to understand that the "squeeze" operation will always reduce the size or leave it intact. In other words, the destination string is always less than or equal to in size as the source string. For these types of algorithms, you can use a standard compacting strategy which involves traversing the array (or string) with two indices (or iterators): one placed at the output position (destination) and one placed at the input position (source).
Finally, to "squeeze" characters, all you really need to do is skip the duplicates.
When understanding these three facts, you get this:
string squeeze(string s, char c)
for(std::size_t i = 0, j = 0; i < s.length(); ++i, ++j)
s[j] = s[i];
while( (i < s.length()) && (s[i] == c) )
return s.substr(0, j);