从字符串中删除括号的C ++函数不会捕获它们

时间:2012-10-05 00:00:40

标签: c++

我在c ++中编写了一个函数来从字符串中删除括号,但它并不总是因为某些原因而将它们全部捕获,我确信它非常简单。

string sanitize(string word)
{
int i = 0;

while(i < word.size())
{
    if(word[i] == '(' || word[i] == ')')
    {
        word.erase(i,1);
    }
    i++;
}
return word;
}

示例结果:

输入:((3)8)8)8)8))7

输出:(38888)7

这是为什么?我可以通过调用输出上的函数来解决问题(因此运行字符串两次),但这显然不是“好”的编程。谢谢!

4 个答案:

答案 0 :(得分:11)

if(word[i] == '(' || word[i] == ')')
{
    word.erase(i,1);
}
i++;

如果删除括号,则下一个字符将移动到先前由括号占据的索引,因此不会检查。使用else

if(word[i] == '(' || word[i] == ')')
{
    word.erase(i,1);
} else {
    i++;
}

答案 1 :(得分:4)

while(i < word.size())
{
    if(word[i] == '(' || word[i] == ')')
    {
        word.erase(i,1);
    }
    i++;
}

删除元素时,下一个元素将移动到该位置。如果要测试它,则必须避免递增计数器:

while (i < word.size()) {
   if (word[i] == '(' || word[i] == ')' ) {
      word.erase(i,1);
   } else {
      ++i;
   }
}

也可以使用迭代器完成,但任何一个选项都不好。对于字符串中的每个括号,将复制之后的所有元素,这意味着您的函数具有二次复杂度:O(N^2)。更好的解决方案是使用 erase-remove 成语:

s.erase( std::remove_if(s.begin(), s.end(), 
                        [](char ch){ return ch==`(` || ch ==`)`; })
         s.end() );

如果您的编译器不支持lambdas,您可以将检查实现为函数对象(仿函数)。此算法具有线性复杂度O(N),因为未删除的元素仅复制一次到最终位置。

答案 2 :(得分:0)

它失败了,因为你在所有情况下递增索引。如果你没有删除这个字符,你应该这样做,因为删除会将超过该点的所有字符移回一个。

换句话说,只要您要删除两个或多个连续字符,就会遇到此问题。它不是同时删除它们,而是将两者“折叠”成一个。

通过你的函数两次运行它会对那个特定的输入字符串起作用,但你仍会遇到类似“((((pax))))”的问题,因为第一次调用会将它折叠为“((pax ))“和第二个会给你”(pax)“。

一种解决方案是在删除字符时推进索引:

std::string sanitize (std::string word) {
    int i = 0;

    while (i < word.size()) {
        if(word[i] == '(' || word[i] == ')') {
            word.erase(i,1);
            continue;
        }
        i++;
    }
    return word;
}

但是,我会更智能地使用该语言的设施。 C ++字符串已经能够搜索一系列字符,这些字符可能比用户循环更优化。所以你可以使用更简单的方法:

std::string sanitize (std::string word) {
    int spos = 0;

    while ((spos = word.find_first_of ("()", spos)) != std::string::npos)
            word.erase (spos, 1);
    return word;
}

您可以在以下完整程序中看到这一点:

#include <iostream>
#include <string>

std::string sanitize (std::string word) {
    int i = 0;

    while ((i = word.find_first_of ("()", i)) != std::string::npos)
            word.erase (i, 1);
    return word;
}

int main (void) {
    std::string s = "((3)8)8)8)8))7 ((((pax))))";
    s = sanitize (s);
    std::cout << s << '\n';
    return 0;
}

输出:

388887 pax

答案 3 :(得分:-2)

为什么不使用strtok和临时字符串?

string sanitize(string word)
{
int i = 0;
 string rVal;
 char * temp;
strtok(word.c_str(), "()"); //I make the assumption that your values should always start with a (
do
{
   temp = strtok(0, "()");
   if(temp == 0)
   {
       break;
   }
   else { rVal += temp;}
}while(1);

return rVal;
}