在 C++ 中怎么去除字符串首尾的空格?怎么去掉字符串中所有的空格?
网上可以查到很多,有用 C 写的,有用纯 C++ 写的,混合的更是大有人在。功能都能实现,但哪个是最佳实践的?有以下几个标准 or 问题?
- 代码足够简洁
- 怎么保证效率?
- 通用性:跨平台
- 要不要考虑 C 调用问题?
一、trim
去除首尾空格,示例代码:
1 |
|
使用 string 的 find_first_not_of()
和 find_last_not_of()
函数找到字符串第一个非空字符和最后一个非空字符的位置,然后进行 erase()
操作。
二、trim_all
在进入主题之前,先来学习两个函数:remove()
和 remove_if()
。
注意这两个函数的“移除”并不完美,他们并不改变容器的大小。一般结合 erase()
同时使用。
Return value
Past-the-end iterator for the new range of values (if this is not end, then it points to an unspecified value, and so do iterators to any values between this iterator and end)
调用 remove()
或 remove_if()
函数会返回移除目标成员之后的区间的尾后迭代器。此迭代器及其后面的元素(如果有的话,一直到原区间的末尾)是不确定的。而这些不确定元素就是我们需要调用 erase()
清理的。看一段代码来理解:
1 |
|
执行结果如下,可以看到移除所有的字符 'e'
之后字符串长度并没有变。删除了3个,就把原字符串末尾的3个字符重复打印了一次(需要强调的是,此行为在其他编译器上不一定会复现,因为 c++ 标准里并未定义)。
1 | vimer@debian8light:~/see-the-world/code/trim_test$ make test CXXFLAGS=-std=c++11 && ./test |
进入正题。我们来看去除所有空白字符的示例代码:
1 |
|
执行结果:
1 | vimer@debian8light:~/see-the-world/code/trim_test$ make test CXXFLAGS=-std=c++11 && ./test |
::isspace
需要强调的是代码中 ::isspace
的作用域前缀,如果使用 isspace
(因为全局 using namespace std;
,所以同 std::isspace
)就会报错。
删除 using namespace std;
,使用 isspace
也是正确的。意义等同 ::isspace
。
::isspace
means you’re explicitly calling the global methodisspace
. The C Standard Library methods are all globals, and<ctype.h>
is a C Standard Library header.Namespaces don’t exist in C, so when using the C library headers, you don’t use the std namespace. The C++ counterpart to
<ctype.h>
which uses the std namespace is<cctype>
. 引用来源
而
std::isspace
is an overloaded function in C++, with a template function declared in<locale>
.
前者没有重载版本;而后者有(一份是 <cctype>
中从 <ctype.h>
拷贝过来加上 std::
作用域的;一份是 <locale>
中的模板函数),参见 isspace-cctype 和 isspace-locale。所以如果使用后者(单独使用函数名,没有参数)就存在指代不明的问题。
为什么明确引入 <cctype>
还是报错,还是存在指代不明的问题呢?另外,示例中未明确引用 <ctype.h>
却未报错是因为什么原因呢?
Implementations are allowed to silently include additional headers you didn’t ask for, and many do so. They do so because they internally make use of those additional headers. 引用来源
如果坚持使用后者需要 解决指代不明的问题 - 使用 lambda:
1 | std::remove_if(str.begin(), str.end(), |
还有几个通过类型转换来解决后者指代不明问题的例子(但和上述的解决方案相比,终非正途):
- http://stackoverflow.com/questions/18589525/removing-all-spaces-from-a-string
- http://stackoverflow.com/questions/4537930/removing-a-character-from-a-string
- http://stackoverflow.com/questions/8364678/g-string-remove-if-error
好吧,我承认,主要是太丑陋了。丑得我都没有仔细看的想法。
总的来说 isspace
::isspace
std::isspace
的问题:
isspace is defined both in the global namespace and in namespace std, so when you have using namespace std, and you write isspace, there’s an ambiguity. To be specific, there’s one overload in
and another defined in . Just write ::isspace and you’re good to go.