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

C++ function to remove parenthesis from string doesn't catch them all

本文关键字:全部 函数 字符串 删除 C++      更新时间:2023-10-16

我用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)7

输出:(38888)7

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

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

如果删除圆括号,下一个字符将移动到该圆括号之前占用的索引,因此不会选中它。使用else

if(word[i] == '(' || word[i] == ')')
{
word.erase(i,1);
} else {
i++;
}
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)。一个更好的解决方案是使用擦除删除习语:

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

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

它失败了,因为在所有情况下都是递增索引。只有在不删除字符的情况下才应该这样做,因为删除会将所有超过该点的字符向后移动一个。

换句话说,只要有两个或多个连续字符要删除,就会出现这个问题。它没有同时删除它们,而是将两者"合并"为一。

在函数中运行两次它将对特定的输入字符串起作用,但您仍然会遇到类似"((((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

为什么不使用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;
}