В настоящее время я использую следующий код для выравнивания всех std::strings
в моих программах:
std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);
Он отлично работает, но мне интересно, есть ли какие-то конечные случаи, где это может закончиться?
Разумеется, приветствуются ответы с элегантными альтернативами, а также с левым отделением.
EDIT. Так как С++ 17, некоторые части стандартной библиотеки были удалены. К счастью, начиная с С++ 11, у нас есть lambdas, которые являются превосходным решением.
#include <algorithm>
#include <cctype>
#include <locale>
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
Благодаря https://stackoverflow.com/questions/44973435/stdptr-fun-replacement-for-c17 для создания современного решения.
Я предпочитаю использовать один из этих 3 для моих нужд обрезки:
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
// trim from start
static inline std::string <rim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}
// trim from end
static inline std::string &rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}
// trim from both ends
static inline std::string &trim(std::string &s) {
return ltrim(rtrim(s));
}
Они достаточно понятны и работают очень хорошо.
РЕДАКТИРОВАТЬ: Кстати, у меня есть std::ptr_fun
, чтобы помочь disambiguate std::isspace
, потому что на самом деле есть второе определение, которое поддерживает локали. Это могло бы быть приведение точно так же, но я предпочитаю это лучше.
РЕДАКТИРОВАТЬ. Чтобы рассмотреть некоторые комментарии о принятии параметра по ссылке, его изменение и его возврат. Согласен. Реализация, которую я, скорее всего, предпочла бы, - это два набора функций: один на месте и один, который делает копию. Лучший пример:
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
Я сохраняю первоначальный ответ выше, хотя для контекста и в интересах сохранения высокого голосованного ответа по-прежнему доступны.
boost::trim
для решения проблемы.
Использование Ускорить строковые алгоритмы было бы проще:
#include <boost/algorithm/string.hpp>
std::string str("hello world! ");
boost::trim_right(str);
str
теперь "hello world!"
. Там также trim_left
и trim
, который обрезает обе стороны.
Если вы добавили суффикс _copy
к любому из перечисленных выше имен функций, например. trim_copy
, функция вернет обрезанную копию строки вместо изменения ее посредством ссылки.
Если вы добавите суффикс _if
к любому из названных имен функций, например. trim_copy_if
, вы можете обрезать все символы, удовлетворяющие вашему пользовательскому предикату, в отличие от просто пробелов.
Используйте следующий код для правых отделочных (конечных) пробелов и символов табуляции из std::strings
(ideone):
// trim trailing spaces
size_t endpos = str.find_last_not_of(" \t");
size_t startpos = str.find_first_not_of(" \t");
if( std::string::npos != endpos )
{
str = str.substr( 0, endpos+1 );
str = str.substr( startpos );
}
else {
str.erase(std::remove(std::begin(str), std::end(str), ' '), std::end(str));
}
И просто для того, чтобы сбалансировать ситуацию, я включу и левый код обрезки (ideone):
// trim leading spaces
size_t startpos = str.find_first_not_of(" \t");
if( string::npos != startpos )
{
str = str.substr( startpos );
}
Бит поздно на вечеринку, но неважно. Теперь С++ 11, у нас есть lambdas и auto variables. Поэтому моя версия, которая также обрабатывает все пробелы и пустые строки, это:
#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 по крайней мере недостаточно умна вывести тип обратного итератора (std::string::const_reverse_iterator
) с помощью auto
. Я не знаю, насколько дорого стоит построение обратного итератора, поэтому здесь 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());
}
То, что вы делаете, прекрасно и надежно. Я использовал один и тот же метод в течение длительного времени, и мне еще предстоит найти более быстрый метод:
const char* ws = " \t\n\r\f\v";
// trim from end of string (right)
inline std::string& rtrim(std::string& s, const char* t = ws)
{
s.erase(s.find_last_not_of(t) + 1);
return s;
}
// trim from beginning of string (left)
inline std::string& ltrim(std::string& s, const char* t = ws)
{
s.erase(0, s.find_first_not_of(t));
return s;
}
// trim from both ends of string (right then left)
inline std::string& trim(std::string& s, const char* t = ws)
{
return ltrim(rtrim(s, t), t);
}
Предоставляя символы, которые нужно обрезать, у вас есть возможность обрезать непробельные символы и эффективно обрезать только те символы, которые вы хотите обрезать.
trim
, то есть сделайте его rtrim(ltrim(s, t), t)
это будет немного более эффективным
Попробуй, это работает для меня.
inline std::string trim(std::string& str)
{
str.erase(0, str.find_first_not_of(' ')); //prefixing spaces
str.erase(str.find_last_not_of(' ')+1); //surfixing spaces
return str;
}
str.find_last_not_of(x)
возвращает позицию первого символа, не равного x. Он возвращает npos только если никакие символы не совпадают с x. В этом примере, если нет пробелов с суффиксами, будет возвращен эквивалент str.length() - 1
, в результате чего str.erase((str.length() - 1) + 1).
существу, str.erase((str.length() - 1) + 1).
То есть, если я не ошибаюсь.
Мне нравится решение tzaman, единственная проблема с ним в том, что он не обрезает строку, содержащую только пробелы.
Чтобы исправить этот недостаток, добавьте str.clear() между двумя линиями триммера
std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;
ltrim
или rtrim
как это.
std::string trim(const std::string &s)
{
std::string::const_iterator it = s.begin();
while (it != s.end() && isspace(*it))
it++;
std::string::const_reverse_iterator rit = s.rbegin();
while (rit.base() != it && isspace(*rit))
rit++;
return std::string(it, rit.base());
}
it
) и наоборот: позиция символа, после которой есть только пробелы ( rit
) - после этого она возвращает вновь созданную строку == копия части исходной строки - части, основанной на этих итераторах ...
В случае пустой строки ваш код предполагает, что добавление 1 в string::npos
дает 0. string::npos
имеет тип string::size_type
, который не имеет знака. Таким образом, вы полагаетесь на поведение при переполнении добавления.
1
в std::string::npos
должно давать 0
соответствии со стандартом C++ Standard
. Так что это хорошее предположение, на которое можно абсолютно положиться.
Снято Cplusplus.com
string choppa(const string &t, const string &ws)
{
string str = t;
size_t found;
found = str.find_last_not_of(ws);
if (found != string::npos)
str.erase(found+1);
else
str.clear(); // str is all whitespace
return str;
}
Это работает и для нулевого случая.: -)
rtrim
, а не ltrim
Мое решение основано на ответе @Bill the Lizard.
Обратите внимание, что эти функции возвращают пустую строку, если строка ввода содержит только пробелы.
const std::string StringUtils::WHITESPACE = " \n\r\t";
std::string StringUtils::Trim(const std::string& s)
{
return TrimRight(TrimLeft(s));
}
std::string StringUtils::TrimLeft(const std::string& s)
{
size_t startpos = s.find_first_not_of(StringUtils::WHITESPACE);
return (startpos == std::string::npos) ? "" : s.substr(startpos);
}
std::string StringUtils::TrimRight(const std::string& s)
{
size_t endpos = s.find_last_not_of(StringUtils::WHITESPACE);
return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
}
Мой ответ - это улучшение в верхнем ответе для этого сообщения, которое обрезает управляющие символы, а также пробелы (0-32 и 127 на Таблица ASCII).
std::isgraph
определяет, имеет ли символ графическое представление, поэтому вы можете использовать это, чтобы изменить ответ Эвана, чтобы удалить любой символ, который doesn Графическое представление с любой стороны строки. Результат - гораздо более элегантное решение:
#include <algorithm>
#include <functional>
#include <string>
/**
* @brief Left Trim
*
* Trims whitespace from the left end of the provided std::string
*
* @param[out] s The std::string to trim
*
* @return The modified std::string&
*/
std::string& ltrim(std::string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::ptr_fun<int, int>(std::isgraph)));
return s;
}
/**
* @brief Right Trim
*
* Trims whitespace from the right end of the provided std::string
*
* @param[out] s The std::string to trim
*
* @return The modified std::string&
*/
std::string& rtrim(std::string& s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::ptr_fun<int, int>(std::isgraph)).base(), s.end());
return s;
}
/**
* @brief Trim
*
* Trims whitespace from both ends of the provided std::string
*
* @param[out] s The std::string to trim
*
* @return The modified std::string&
*/
std::string& trim(std::string& s) {
return ltrim(rtrim(s));
}
Примечание: В качестве альтернативы вы можете использовать std::iswgraph
, если вам нужна поддержка широких символов, но вам также придется отредактировать этот код, чтобы активировать манипуляцию std::wstring
, что я не тестировал (см. справочную страницу для std::basic_string
, чтобы изучить этот вариант).
s.erase(0, s.find_first_not_of(" \n\r\t"));
s.erase(s.find_last_not_of(" \n\r\t")+1);
Для того, что стоит, вот реализация отделки с прицелом на производительность. Это намного быстрее, чем многие другие подпрограммы, которые я видел вокруг. Вместо использования итераторов и std:: find используется строковые строки и индексы. Он оптимизирует следующие особые случаи: строка размера 0 (ничего не делать), строка без пробелов для обрезки (ничего не делать), строка с только завершающим пробелом для обрезки (просто изменить размер строки), строка целиком пробела (просто очистите строку), И, наконец, в худшем случае (строка с ведущими пробелами) она делает все возможное, чтобы выполнить эффективную конструкцию копирования, выполняя только одну копию, а затем перемещая эту копию вместо исходной строки.
void TrimString(std::string & str)
{
if(str.empty())
return;
const auto pStr = str.c_str();
size_t front = 0;
while(front < str.length() && std::isspace(int(pStr[front]))) {++front;}
size_t back = str.length();
while(back > front && std::isspace(int(pStr[back-1]))) {--back;}
if(0 == front)
{
if(back < str.length())
{
str.resize(back - front);
}
}
else if(back <= front)
{
str.clear();
}
else
{
str = std::move(std::string(str.begin()+front, str.begin()+back));
}
}
Это то, что я использую. Просто продолжайте удалять пространство спереди, а затем, если что-то осталось, сделайте то же самое со спины.
void trim(string& s) {
while(s.compare(0,1," ")==0)
s.erase(s.begin()); // remove leading whitespaces
while(s.size()>0 && s.compare(s.size()-1,1," ")==0)
s.erase(s.end()-1); // remove trailing whitespaces
}
Элегантный способ сделать это может быть как
std::string & trim(std::string & str)
{
return ltrim(rtrim(str));
}
И вспомогательные функции реализованы как:
std::string & ltrim(std::string & str)
{
auto it = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( str.begin() , it);
return str;
}
std::string & rtrim(std::string & str)
{
auto it = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( it.base() , str.end() );
return str;
}
И как только вы все это на месте, вы также можете написать это:
std::string trim_copy(std::string const & str)
{
auto s = str;
return ltrim(rtrim(s));
}
С С++ 11 также появился модуль регулярных выражений, который, конечно, можно использовать для обрезки ведущих или конечных пробелов.
Может быть, что-то вроде этого:
std::string ltrim(const std::string& s)
{
static const std::regex lws{"^[[:space:]]*", std::regex_constants::extended};
return std::regex_replace(s, lws, "");
}
std::string rtrim(const std::string& s)
{
static const std::regex tws{"[[:space:]]*$", std::regex_constants::extended};
return std::regex_replace(s, tws, "");
}
std::string trim(const std::string& s)
{
return ltrim(rtrim(s));
}
Выполнение Trim С++ 11:
static void trim(std::string &s) {
s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), [](char c){ return std::isspace(c); }));
s.erase(std::find_if_not(s.rbegin(), s.rend(), [](char c){ return std::isspace(c); }).base(), s.end());
}
Я думаю, если вы начнете просить "лучший способ" обрезать строку, я бы сказал, что хорошая реализация будет такой:
Очевидно, существует слишком много разных способов приблизиться к этому, и это определенно зависит от того, что вам действительно нужно. Однако стандартная библиотека C по-прежнему имеет некоторые очень полезные функции в < string.h > , например memchr. Там причина, по которой C по-прежнему считается лучшим языком для IO - его stdlib - это чистая эффективность.
inline const char* trim_start(const char* str)
{
while (memchr(" \t\n\r", *str, 4)) ++str;
return str;
}
inline const char* trim_end(const char* end)
{
while (memchr(" \t\n\r", end[-1], 4)) --end;
return end;
}
inline std::string trim(const char* buffer, int len) // trim a buffer (input?)
{
return std::string(trim_start(buffer), trim_end(buffer + len));
}
inline void trim_inplace(std::string& str)
{
str.assign(trim_start(str.c_str()),
trim_end(str.c_str() + str.length()));
}
int main()
{
char str [] = "\t \nhello\r \t \n";
string trimmed = trim(str, strlen(str));
cout << "'" << trimmed << "'" << endl;
system("pause");
return 0;
}
Вот моя версия:
size_t beg = s.find_first_not_of(" \r\n");
return (beg == string::npos) ? "" : in.substr(beg, s.find_last_not_of(" \r\n") - beg);
Это проще сделать в С++ 11 из-за добавления back()
и pop_back()
.
while ( !s.empty() && isspace(s.back()) ) s.pop_back();
Внесение моего решения в шум. trim
по умолчанию создает новую строку и возвращает измененную, а trim_in_place
изменяет переданную ей строку. Функция trim
поддерживает семантику перемещения С++ 11.
#include <string>
// modifies input string, returns input
std::string& trim_left_in_place(std::string& str) {
size_t i = 0;
while(i < str.size() && isspace(str[i])) { ++i; };
return str.erase(0, i);
}
std::string& trim_right_in_place(std::string& str) {
size_t i = str.size();
while(i > 0 && isspace(str[i - 1])) { --i; };
return str.erase(i, str.size());
}
std::string& trim_in_place(std::string& str) {
return trim_left_in_place(trim_right_in_place(str));
}
// returns newly created strings
std::string trim_right(std::string str) {
return trim_right_in_place(str);
}
std::string trim_left(std::string str) {
return trim_left_in_place(str);
}
std::string trim(std::string str) {
return trim_left_in_place(trim_right_in_place(str));
}
#include <cassert>
int main() {
std::string s1(" \t\r\n ");
std::string s2(" \r\nc");
std::string s3("c \t");
std::string s4(" \rc ");
assert(trim(s1) == "");
assert(trim(s2) == "c");
assert(trim(s3) == "c");
assert(trim(s4) == "c");
assert(s1 == " \t\r\n ");
assert(s2 == " \r\nc");
assert(s3 == "c \t");
assert(s4 == " \rc ");
assert(trim_in_place(s1) == "");
assert(trim_in_place(s2) == "c");
assert(trim_in_place(s3) == "c");
assert(trim_in_place(s4) == "c");
assert(s1 == "");
assert(s2 == "c");
assert(s3 == "c");
assert(s4 == "c");
}
Вот что я придумал:
std::stringstream trimmer;
trimmer << str;
trimmer >> str;
Извлечение потока автоматически удаляет пробелы, так что это работает как шарм.
Довольно чистый и элегантный тоже, если я так говорю сам.;)
Я не уверен, что ваша среда такая же, но в моем случае пустая строка приведет к прерыванию программы. Я бы либо обернул этот стирающий вызов с if (! S.empty()), либо использовал Boost, как уже упоминалось.
Вышеупомянутые методы великолепны, но иногда вы хотите использовать комбинацию функций для того, что ваша рутина считает пробелом. В этом случае использование функторов для объединения операций может стать беспорядочным, поэтому я предпочитаю простой цикл, который я могу изменить для обрезки. Вот слегка модифицированная функция trim, скопированная из версии C здесь, на SO. В этом примере я обрезаю не буквенно-цифровые символы.
string trim(char const *str)
{
// Trim leading non-letters
while(!isalnum(*str)) str++;
// Trim trailing non-letters
end = str + strlen(str) - 1;
while(end > str && !isalnum(*end)) end--;
return string(str, end+1);
}
Здесь легко понять начинающих, которые не использовали для записи std::
всюду и еще не знакомы с const
-корректностью, iterator
s, STL algorithm
s и т.д.
#include <string>
#include <cctype> // for isspace
using namespace std;
// Left trim the given string (" hello! " --> "hello! ")
string left_trim(string str) {
int numStartSpaces = 0;
for (int i = 0; i < str.length(); i++) {
if (!isspace(str[i])) break;
numStartSpaces++;
}
return str.substr(numStartSpaces);
}
// Right trim the given string (" hello! " --> " hello!")
string right_trim(string str) {
int numEndSpaces = 0;
for (int i = str.length() - 1; i >= 0; i--) {
if (!isspace(str[i])) break;
numEndSpaces++;
}
return str.substr(0, str.length() - numEndSpaces);
}
// Left and right trim the given string (" hello! " --> "hello!")
string trim(string str) {
return right_trim(left_trim(str));
}
Надеюсь, что это поможет...
Вот прямая реализация. Для такой простой операции вы, вероятно, не должны использовать какие-либо специальные конструкции. Функция build-in isspace() выполняет различные формы белых символов, поэтому мы должны использовать ее. Вы также должны учитывать особые случаи, когда строка пуста или просто пучок пробелов. Обрезка влево или вправо может быть получена из следующего кода.
string trimSpace(const string &str) {
if (str.empty()) return str;
string::size_type i,j;
i=0;
while (i<str.size() && isspace(str[i])) ++i;
if (i == str.size())
return string(); // empty string
j = str.size() - 1;
//while (j>0 && isspace(str[j])) --j; // the j>0 check is not needed
while (isspace(str[j])) --j
return str.substr(i, j-i+1);
}
Как я хотел обновить мою старую функцию С++ trim с помощью подхода С++ 11, я проверил множество опубликованных ответов на вопрос. Я пришел к выводу, что сохраняю свое старое решение на C++!
Это самый быстрый из них, даже добавляя больше символов для проверки (например,\r\n Я не вижу случая использования для \f\v) все еще быстрее, чем решения, использующие алгоритм.
std::string & trimMe (std::string & str)
{
// right trim
while (str.length () > 0 && (str [str.length ()-1] == ' ' || str [str.length ()-1] == '\t'))
str.erase (str.length ()-1, 1);
// left trim
while (str.length () > 0 && (str [0] == ' ' || str [0] == '\t'))
str.erase (0, 1);
return str;
}
Как насчет этого...?
#include <iostream>
#include <string>
#include <regex>
std::string ltrim( std::string str ) {
return std::regex_replace( str, std::regex("^\\s+"), std::string("") );
}
std::string rtrim( std::string str ) {
return std::regex_replace( str, std::regex("\\s+$"), std::string("") );
}
std::string trim( std::string str ) {
return ltrim( rtrim( str ) );
}
int main() {
std::string str = " \t this is a test string \n ";
std::cout << "-" << trim( str ) << "-\n";
return 0;
}
Примечание. Я все еще относительно новичок в С++, поэтому, пожалуйста, простите меня, если я здесь не нахожусь.
regex
для обрезки немного излишне.
Еще один вариант - удаляет один или несколько символов с обоих концов.
string strip(const string& s, const string& chars=" ") {
size_t begin = 0;
size_t end = s.size()-1;
for(; begin < s.size(); begin++)
if(chars.find_first_of(s[begin]) == string::npos)
break;
for(; end > begin; end--)
if(chars.find_first_of(s[end]) == string::npos)
break;
return s.substr(begin, end-begin+1);
}
Эта версия обрезает внутренние пробелы и не-буквенно-цифровые символы:
static inline std::string &trimAll(std::string &s)
{
if(s.size() == 0)
{
return s;
}
int val = 0;
for (int cur = 0; cur < s.size(); cur++)
{
if(s[cur] != ' ' && std::isalnum(s[cur]))
{
s[val] = s[cur];
val++;
}
}
s.resize(val);
return s;
}
В С++ 17 вы можете использовать basic_string_view :: remove_prefix и basic_string_view :: remove_suffix:
std::string_view trim(std::string_view s) const
{
s.remove_prefix(std::min(s.find_first_not_of(" \t\r\v\n"), s.size()));
s.remove_suffix((s.size() - 1) - std::min(s.find_last_not_of(" \t\r\v\n"), s.size() - 1));
return s;
}
Ниже представлен один проход (может быть двухпроходный). Он пробегает часть пробелов в строке дважды и не-пробельную часть один раз.
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;
}
Я знаю, что это очень старый вопрос, но я добавил несколько строк кода к вашему, и он обрезает пробелы с обоих концов.
void trim(std::string &line){
auto val = line.find_last_not_of(" \n\r\t") + 1;
if(val == line.size() || val == std::string::npos){
val = line.find_first_not_of(" \n\r\t");
line = line.substr(val);
}
else
line.erase(val);
}
С++ 11:
int i{};
string s = " h e ll \t\n o";
string trim = " \n\t";
while ((i = s.find_first_of(trim)) != -1)
s.erase(i,1);
cout << s;
выход:
hello
отлично работает и с пустыми строками
Я использую этот:
void trim(string &str){
int i=0;
//left trim
while (isspace(str[i])!=0)
i++;
str = str.substr(i,str.length()-i);
//right trim
i=str.length()-1;
while (isspace(str[i])!=0)
i--;
str = str.substr(0,i+1);
}
Это хорошо? (Причина этого сообщения полностью нуждается в другом ответе:)
string trimBegin(string str)
{
string whites = "\t\r\n ";
int i = 0;
while (whites.find(str[i++]) != whites::npos);
str.erase(0, i);
return str;
}
Аналогичный случай для trimEnd, просто измените поляризатор, индексы.
while (isspace(str[i++]));
для ясности. На самом деле самым большим мотивирующим фактором является то, что мне пришлось читать некоторую документацию, чтобы понять код, потому что я изначально думал, что это имеет порядок сложности O (n ^ 2) (чего, как вы знаете, нет). Затем код можно сократить до string trimBegin(string str) { size_t i = 0; while(isspace(str[i++]); return str.erase(0, i); }
std::string trim( std::string && str )
{
size_t end = str.find_last_not_of( " \n\r\t" );
if ( end != std::string::npos )
str.resize( end + 1 );
size_t start = str.find_first_not_of( " \n\r\t" );
if ( start != std::string::npos )
str = str.substr( start );
return std::move( str );
}
Кажется, я очень опаздываю на вечеринку - я не могу поверить, что это было спрошено 7 лет назад!
Здесь я беру на себя эту проблему. Я работаю над проектом, и сейчас я не хочу беспокоиться об использовании Boost.
std::string trim(std::string str) {
if(str.length() == 0) return str;
int beg = 0, end = str.length() - 1;
while (str[beg] == ' ') {
beg++;
}
while (str[end] == ' ') {
end--;
}
return str.substr(beg, end - beg + 1);
}
Это решение будет обрезать слева и справа.
Это так раздражает, что я
Для меня это самый быстрый способ его решения:
CString tmp(line.c_str());
tmp = tmp.Trim().MakeLower();
string buffer = tmp;
Хорошо, это здорово, что я могу использовать лямбда-операторы, итераторы и все прочее. Но мне нужно иметь дело только со строкой, а не с символом...
CString
- это мерзость для MFC / ATL, характерная для Windows (которая, вероятно, ближе к «ракетостроению», чем несколько строк стандарта C ++ без сторонних зависимостей). Вы не можете предполагать, что кто-то может использовать это, или даже хочет использовать это.