I want to delete all characters between two same characters in a string. My function takes a string (by reference) and a char in its arguments.
我想删除字符串中两个相同字符之间的所有字符。我的函数在其参数中使用一个字符串(通过引用)和一个char。
Assuming that I used an std::string
variable like this: "hah haaah hah hello!"
as the first parameter and a char 'h'
as the second parameter, something like this should happen: "hah haaah hah hello!" ===> "hh hh hh hello"
. As you can see, every character between two h
characters has been removed. How do I achive something like this?
假设我使用了这样的std :: string变量:“hah haaah hah hello!”作为第一个参数和char'h'作为第二个参数,这样的事情应该发生:“hah haaah hah hello!” ===>“嗯......你好”。如您所见,两个h字符之间的每个字符都已被删除。我怎么做这样的事情?
I've tried to use iterators and ended up with this:
我试过使用迭代器并最终得到这个:
void delete_chars_between(std::string& line, char del)
{
std::string::iterator itr_from = std::find(line.begin(), line.end(), del);
std::string::iterator itr_to = std::find(itr_from + 1, line.end(), del);
while (true) {
if(itr_to != line.end())
line.erase(itr_from + 1, itr_to);
itr_from = std::find(itr_to, line.end(), del);
if (itr_from == line.end())
break;
itr_to = std::find(itr_from + 1, line.end(), del);
if (itr_to == line.end())
break;
}
}
First, I search for the first occurrence of del
, I store the iterator to its position in itr_from
. After that, I search for the second occurrence of del
. And finally I run a while loop that starts by erasing characters in a certain range if itr_to
is valid. I repeat that over and over again while my iterators are not equal to line.end()
.
首先,我搜索del的第一次出现,我将迭代器存储到itr_from中的位置。之后,我搜索del的第二次出现。最后,如果itr_to有效,我会运行一个while循环,首先擦除某个范围内的字符。我一遍又一遍地重复这一点,而我的迭代器不等于line.end()。
But for some reason, this code doesn't work properly. It sometimes removes whitespaces and doesn't even touch the characters I was aiming to delete.
但由于某些原因,此代码无法正常工作。它有时会删除空格,甚至不会触及我想要删除的字符。
Thanks for your help.
谢谢你的帮助。
2 个解决方案
#1
3
std::string
iterators are invalidated by all operations which modify the length of the string, so using itr_from
and itr_to
after the call to line.erase
is Undefined Behaviour.
所有修改字符串长度的操作都会使std :: string迭代器失效,因此在调用line.erase之后使用itr_from和itr_to是Undefined Behavior。
You need to use the return value of erase
:
你需要使用erase的返回值:
while (true) {
if(itr_to != line.end())
itr_to = line.erase(itr_from + 1, itr_to);
itr_from = std::find(itr_to, line.end(), del);
if (itr_from == line.end())
break;
itr_to = std::find(itr_from + 1, line.end(), del);
if (itr_to == line.end())
break;
}
#2
0
To avoid undefined behavior you should reset both iterators before calling erase
.
为避免未定义的行为,您应在调用erase之前重置两个迭代器。
Looking at the expected output it seems that a closing delimiter shouldn't be used to start another interval:
查看预期的输出似乎不应该使用结束分隔符来启动另一个间隔:
"hh hh hh hello" not "hhhhhhhello"
^ ^ ^
So, this is my proposal:
所以,这是我的建议:
void delete_chars_between(std::string& line, char del)
{
std::string::iterator itr_from = std::find(line.begin(), line.end(), del);
// I don't want to pass an iterator to two past the last element
if ( itr_from == line.end() )
return;
std::string::iterator itr_to = std::find(itr_from + 1, line.end(), del);
// ^^^^
while ( itr_to != line.end() )
{
itr_to = line.erase(itr_from + 1, itr_to);
itr_from = std::find(itr_to + 1, line.end(), del);
// to start another couple ^^^^
if (itr_from == line.end())
break;
itr_to = std::find(itr_from + 1, line.end(), del);
}
}
Live example HERE.
这里有实例。
#1
3
std::string
iterators are invalidated by all operations which modify the length of the string, so using itr_from
and itr_to
after the call to line.erase
is Undefined Behaviour.
所有修改字符串长度的操作都会使std :: string迭代器失效,因此在调用line.erase之后使用itr_from和itr_to是Undefined Behavior。
You need to use the return value of erase
:
你需要使用erase的返回值:
while (true) {
if(itr_to != line.end())
itr_to = line.erase(itr_from + 1, itr_to);
itr_from = std::find(itr_to, line.end(), del);
if (itr_from == line.end())
break;
itr_to = std::find(itr_from + 1, line.end(), del);
if (itr_to == line.end())
break;
}
#2
0
To avoid undefined behavior you should reset both iterators before calling erase
.
为避免未定义的行为,您应在调用erase之前重置两个迭代器。
Looking at the expected output it seems that a closing delimiter shouldn't be used to start another interval:
查看预期的输出似乎不应该使用结束分隔符来启动另一个间隔:
"hh hh hh hello" not "hhhhhhhello"
^ ^ ^
So, this is my proposal:
所以,这是我的建议:
void delete_chars_between(std::string& line, char del)
{
std::string::iterator itr_from = std::find(line.begin(), line.end(), del);
// I don't want to pass an iterator to two past the last element
if ( itr_from == line.end() )
return;
std::string::iterator itr_to = std::find(itr_from + 1, line.end(), del);
// ^^^^
while ( itr_to != line.end() )
{
itr_to = line.erase(itr_from + 1, itr_to);
itr_from = std::find(itr_to + 1, line.end(), del);
// to start another couple ^^^^
if (itr_from == line.end())
break;
itr_to = std::find(itr_from + 1, line.end(), del);
}
}
Live example HERE.
这里有实例。