remove_if字符串中的最后一个字符

时间:2016-04-20 09:42:24

标签: c++ string algorithm c++11 stl

我想删除引用字符串传递的第一个和最后一个括号。不幸的是,我有条件地删除第一个和最后一个元素。 我无法理解为什么remove_if没有按照我对迭代器的预期工作。

Demo

#include <iostream>
#include <algorithm>
using namespace std;

void print_wo_brackets(string& str){
    auto detect_bracket = [](char x){ return(')' == x || '(' == x);};
    if (!str.empty()) 
    {
        str.erase(std::remove_if(str.begin(), str.begin() + 1, detect_bracket));
    }
    if (!str.empty()) 
    {
        str.erase(std::remove_if(str.end()-1, str.end(), detect_bracket));
    }
}

int main()
{
    string str = "abc)";
    cout << str << endl;
    print_wo_brackets(str);
    cout << str << endl;


    string str2 = "(abc";
    cout << str2 << endl;
    print_wo_brackets(str2);
    cout << str2 << endl;

    return 0;
}

输出

abc)
ac    <- HERE I expect abc 
(abc 
abc

5 个答案:

答案 0 :(得分:6)

如果remove_if返回end迭代器,那么您将尝试擦除不存在的元素。您应该在两个地方使用erase版本作为范围:

void print_wo_brackets(string& str){
    auto detect_bracket = [](char x){ return(')' == x || '(' == x);};
    if (!str.empty())
    {
        str.erase(std::remove_if(str.begin(), str.begin() + 1, detect_bracket), str.begin() + 1);
    }
    if (!str.empty())
    {
        str.erase(std::remove_if(str.end()-1, str.end(), detect_bracket), str.end());
    }
}

答案 1 :(得分:4)

问题在于:

if (!str.empty()) 
{
    str.erase(std::remove_if(str.begin(), str.begin() + 1, detect_bracket));
}

你无条件地擦除。 std::remove_if将迭代器返回到“for removal”范围的开头。如果没有要删除的元素,则返回范围的结尾(在这种情况下为str.begin() + 1)。因此,您删除了begin+1元素,b

为了防止出现这个问题,你不应该做更多的事情:

if (!str.empty()) 
{
    auto it = std::remove_if(str.begin(), str.begin() + 1, detect_bracket);
    if(it != str.begin() + 1)
        str.erase(it);
}

我假设您只想检查标准库和迭代器的行为,否则请检查:

if(str[0] == '(' || str[0] == ')')
    str.erase(0);

更简单。

答案 2 :(得分:3)

替代:

#include <iostream>
#include <string>

std::string without_brackets(std::string str, char beg = '(', char end = ')') {
    auto last = str.find_last_of(end);
    auto first = str.find_first_of(beg);

    if(last != std::string::npos) {
        str.erase(str.begin()+last);
    }
    if(first != std::string::npos) {
        str.erase(str.begin()+first);
    }

    return str;
}


using namespace std;

int main() {
    cout << without_brackets("abc)") << endl
         << without_brackets("(abc") << endl
         << without_brackets("(abc)") << endl
         << without_brackets("abc") << endl;
    return 0;
}

请参阅:http://ideone.com/T2bZDe

结果:

abc
abc
abc
abc

答案 3 :(得分:2)

如@PeteBecker的评论中所述,remove_if不是正确的算法。由于您只想删除匹配的第一个和最后一个字符,因此更简单的方法是针对两个括号back()front()(括号)测试()将是[]

void remove_surrounding(string& str, char left = '(', char right = ')')
{
    if (!str.empty() && str.front() == left)
        str.erase(str.begin());
    if (!str.empty() && str.back() == right)
        str.erase(str.end() - 1);
}

Live Example

答案 4 :(得分:1)

所有你需要的是:

void print_wo_brackets(string& str){
  str.erase(std::remove_if(str.begin(), str.end(),
    [&](char &c) { return (c == ')' || c == '(') && (&c == str.data() || &c == (str.data() + str.size() - 1));}), str.end());
}

Live Demo

陈述:

str.erase(std::remove_if(str.end()-1, str.end(), detect_bracket));

你引起了未定义的行为。