我目前正在使用以下代码在我的程序中右修剪所有std::字符串:
std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);
它工作得很好,但我想知道是否有一些最终情况下它可能会失败?
当然,有优雅的选择和左修剪解决方案的答案是受欢迎的。
我目前正在使用以下代码在我的程序中右修剪所有std::字符串:
std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);
它工作得很好,但我想知道是否有一些最终情况下它可能会失败?
当然,有优雅的选择和左修剪解决方案的答案是受欢迎的。
当前回答
我认为在这个例子中使用宏是一个很好的实践:(适用于c++ 98)
#define TRIM_CHARACTERS " \t\n\r\f\v"
#define TRIM_STRING(given) \
given.erase(given.find_last_not_of(TRIM_CHARACTERS) + 1); \
given.erase(0, given.find_first_not_of(TRIM_CHARACTERS));
例子:
#include <iostream>
#include <string>
#define TRIM_CHARACTERS " \t\n\r\f\v"
#define TRIM_STRING(given) \
given.erase(given.find_last_not_of(TRIM_CHARACTERS) + 1); \
given.erase(0, given.find_first_not_of(TRIM_CHARACTERS));
int main(void) {
std::string text(" hello world!! \t \r");
TRIM_STRING(text);
std::cout << text; // "hello world!!"
}
其他回答
有点晚了,不过没关系。c++ 11在这里,我们有lambda和auto变量。所以我的版本,也处理全空白和空字符串,是:
#include <cctype>
#include <string>
#include <algorithm>
inline std::string trim(const std::string &s)
{
auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
auto wsback=std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base();
return (wsback<=wsfront ? std::string() : std::string(wsfront,wsback));
}
我们可以从wsfront创建一个反向迭代器,并在第二个find_if_not中使用它作为终止条件,但这只在全空白字符串的情况下有用,gcc 4.8至少不足以用auto推断反向迭代器(std::string::const_reverse_iterator)的类型。我不知道构造反向迭代器有多贵,这里是YMMV。修改后,代码如下所示:
inline std::string trim(const std::string &s)
{
auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
return std::string(wsfront,std::find_if_not(s.rbegin(),std::string::const_reverse_iterator(wsfront),[](int c){return std::isspace(c);}).base());
}
我认为在这个例子中使用宏是一个很好的实践:(适用于c++ 98)
#define TRIM_CHARACTERS " \t\n\r\f\v"
#define TRIM_STRING(given) \
given.erase(given.find_last_not_of(TRIM_CHARACTERS) + 1); \
given.erase(0, given.find_first_not_of(TRIM_CHARACTERS));
例子:
#include <iostream>
#include <string>
#define TRIM_CHARACTERS " \t\n\r\f\v"
#define TRIM_STRING(given) \
given.erase(given.find_last_not_of(TRIM_CHARACTERS) + 1); \
given.erase(0, given.find_first_not_of(TRIM_CHARACTERS));
int main(void) {
std::string text(" hello world!! \t \r");
TRIM_STRING(text);
std::cout << text; // "hello world!!"
}
下面是一个通道(可能是两个通道)的解决方案。它遍历字符串的空白部分两次,非空白部分一次。
void trim(std::string& s) {
if (s.empty())
return;
int l = 0, r = s.size() - 1;
while (l < s.size() && std::isspace(s[l++])); // l points to first non-whitespace char.
while (r >= 0 && std::isspace(s[r--])); // r points to last non-whitespace char.
if (l > r)
s = "";
else {
l--;
r++;
int wi = 0;
while (l <= r)
s[wi++] = s[l++];
s.erase(wi);
}
return;
}
为什么不用?
auto no_space = [](char ch) -> bool {
return !std::isspace<char>(ch, std::locale::classic());
};
auto ltrim = [](std::string& s) -> std::string& {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), no_space));
return s;
};
auto rtrim = [](std::string& s) -> std::string& {
s.erase(std::find_if(s.rbegin(), s.rend(), no_space).base(), s.end());
return s;
};
auto trim_copy = [](std::string s) -> std::string& { return ltrim(rtrim(s)); };
auto trim = [](std::string& s) -> std::string& { return ltrim(rtrim(s)); };
在空字符串的情况下,你的代码假设将1添加到string::npos得到0。String::npos的类型是String::size_type,无符号。因此,您依赖于加法的溢出行为。