web-dev-qa-db-ja.com

Std :: stringをトリミングするための最良の方法は何ですか?

私は現在、私のプログラムのすべてのstd::stringsを右トリムするために次のコードを使用しています。

std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);

うまくいきますが、失敗する可能性がある最終的なケースがあるのでしょうか。

もちろん、洗練された代替案や左揃えの解決策での回答も大歓迎です。

712
Milan Babuškov

_ edit _ c ++ 17以降、標準ライブラリの一部が削除されました。幸いなことに、c ++ 11から始めて、私たちは優れた解決策であるラムダを持っています。

#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/a/44973498/524503 に近代的な解決策をもたらしてくれてありがとう。

元の答え:

私は私のトリミングニーズにこれら3つのうちの1つを使用する傾向があります。

#include <algorithm> 
#include <functional> 
#include <cctype>
#include <locale>

// trim from start
static inline std::string &ltrim(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));
}

それらはかなり自明で、とてもうまく機能します。

_ edit _ :ところで、ロケールをサポートする2番目の定義が実際にあるのでstd::ptr_funを明確にするのを助けるためにそこにstd::isspaceがあります。これはまったく同じキャストである可能性がありますが、私はこれを好む傾向があります。

_ edit _ :参照によるパラメータの受け入れ、変更および返却に関するコメントに対処する。同意する。私が好むと思う実装は2組の機能、その1つはインプレース用、もう1つはコピーを作成することです。より良い例は次のようになります。

#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;
}

私は上記の元の答えを文脈のためにそして高投票の答えがまだ利用可能であり続けることの利益のために保っています。

580
Evan Teran

Boostの文字列アルゴリズム を使うのが最も簡単でしょう。

#include <boost/algorithm/string.hpp>

std::string str("hello world! ");
boost::trim_right(str);

str"hello world!"になりました。両側をトリミングするtrim_lefttrimもあります。


上記の関数名のいずれかに_copyサフィックスを追加すると、 trim_copyは、関数は参照を通してそれを修正する代わりに文字列のトリミングされたコピーを返します。

上記の関数名のいずれかに_ifサフィックスを追加すると、 trim_copy_ifでは、空白だけではなく、カスタム述語を満たすすべての文字をトリミングできます。

396
Leon Timmermans

次のコードを使用して、std::stringsideone )のスペースとタブ文字を右端(末尾)にトリミングします。

// 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 );
}
59
Bill the Lizard

パーティーに遅刻しますが、気にしないでください。 C++ 11ができました。ラムダと自動変数があります。それで私のバージョンは全空白文字と空の文字列も扱います:

#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から逆方向反復子を作成し、それを2番目の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());
}
51
David G

あなたがしていることは、元気で頑強です。私は長い間同じ方法を使用してきましたが、もっと早い方法をまだ見つけていません。

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);
}

切り捨てられる文字を指定することで、空白以外の文字を切り捨てる柔軟性と、切り取りたい文字だけを切り取る効率が得られます。

39
Galik

これを試して、それは私のために働く。

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;
}
34
user818330

私はtzamanの解決策が好きです、それに関する唯一の問題はそれがスペースだけを含む文字列をトリムしないということです。

この1つの欠陥を修正するには、2つのトリマーラインの間にstr.clear()を追加します。

std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;
25

http://ideone.com/nFVtEo

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());
}
19
Pushkoff

空の文字列の場合、コードはstring::nposに1を加えると0になると想定します。string::nposstring::size_type型で、符号なしです。したがって、加算のオーバーフロー動作に頼っています。

15
Greg Hewgill

Cplusplus.com のハッキング

std::string choppa(const std::string &t, const std::string &ws)
{
    std::string str = t;
    size_t found;
    found = str.find_last_not_of(ws);
    if (found != std::string::npos)
        str.erase(found+1);
    else
        str.clear();            // str is all whitespace

    return str;
}

これはnullの場合にも同様に機能します。 :-)

14
Paul Nathan

私の解決策は に基づいて@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);
}
10
DavidRR

私の答えは、この投稿の トップの回答 を改善したものです。これは、コントロール文字とスペース( ASCIIテーブルでは0-32と127 )を削除します。

std::isgraph は文字がグラフィック表現を持つかどうかを決定するので、これを使って文字列の両側からグラフィック表現を持たない文字を削除するためにEvanの答えを変更することができます。その結果、はるかに洗練された解決策が得られます。

#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 の参照ページを参照してください)。

9
Clay Freeman

C++ 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));
}

これが私が使っているものです。正面からスペースを取り去り、その後、何か残っている場合は、背面から同じようにします。

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
}
7
synaptik

その価値があるのは、パフォーマンスを見据えたトリム実装です。それは私が周りで見た他の多くのトリムルーチンよりはるかに速いです。イテレータとstd :: findを使う代わりに、生のc文字列とインデックスを使います。次の特殊なケースを最適化します。size 0文字列(何もしない)、空白を含まない文字列(何もしない)、末尾の空白文字のみを含む文字列(文字列のサイズを変更する)、完全に空白の文字列(文字列をクリアする) 。そして最後に、最悪の場合(先行空白を含む文字列)、効率的なコピー構築を行い、1回のコピーだけを実行してから元の文字列の代わりにそのコピーを移動するのが最善です。

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));
    }
}
7
mbgda
s.erase(0, s.find_first_not_of(" \n\r\t"));                                                                                               
s.erase(s.find_last_not_of(" \n\r\t")+1);   
7
freeboy1015

それをする優雅な方法はのようである場合もあります

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));
}
6
gjha

C++ 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());
}
5
GutiMac

C++ 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;
}
4
Phidelux

あなたが文字列をトリミングするための「最善の方法」を求め始めたら、私は良い実装がそれであると言うでしょう:

  1. 一時的な文字列を割り当てません
  2. インプレーストリムおよびコピートリムに過負荷がある
  3. 異なる検証シーケンス/ロジックを受け入れるように簡単にカスタマイズ可能

明らかにこれに近づくには多種多様な方法があり、それは間違いなくあなたが実際に必要なものに依存します。しかし、C標準ライブラリには、memchrのように、<string.h>にまだ非常に便利な関数がいくつかあります。 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;
}
4
Jorma Rebane

騒音に対する私の解決策に貢献してください。 trimはデフォルトで新しい文字列を作成し、変更された文字列を返すのに対してtrim_in_placeは渡された文字列を変更します。 trim関数は、c ++ 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");  
}
3
vmrob

あなたの環境が同じであるかどうか私にはわかりませんが、私の考えでは、空文字列の場合はプログラムが中断されます。その消去呼び出しをif(!s.empty())でラップするか、既に述べたようにBoostを使用します。

3
Steve

これが私が思いついたものです:

std::stringstream trimmer;
trimmer << str;
trimmer >> str;

ストリーム抽出は空白を自動的に削除するので、これは魅力的なように機能します。
私がそう言うのであれば、かなり清潔でエレガントでもあります。 ;)

3
tzaman

back() および pop_back() が追加されているため、C++ 11ではこれをより簡単に行うことができます。

while ( !s.empty() && isspace(s.back()) ) s.pop_back();
3
nobar

これが私のバージョンです:

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);
3
nulleight

上記の方法は素晴らしいですが、ルーチンが空白と見なすために関数の組み合わせを使いたいことがあります。この場合、ファンクタを使って操作を組み合わせるのは面倒になることがあるので、私はトリム用に変更できる単純なループを好みます。これは、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);
}
2
Corwin Joy

このバージョンでは、内部の空白文字と英数字以外の文字が削除されます。

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;
}
1
Brian

さらに別のオプション - 両端から1つ以上の文字を削除します。

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);
}
1
Brian W.

これは、どこにでもstd::を書くのに慣れておらず、まだconst-correctness、iterators、STL algorithmsなどに慣れていない初心者にとって理解しやすいソリューションです。

#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));
}

それが役に立てば幸い...

1
cute_ptr

私はC++ 11のアプローチで私の古いC++トリム関数を更新したいので、私は質問に対して投稿された答えの多くをテストしました。私の結論は、私は私の古い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;
     }
1
elxala

これはどうですか...?

#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;

}

注意:私はまだC++に比較的慣れていません。

1
Duncan

これは簡単な実装です。このような単純な操作では、おそらく特別な構成要素を使用してはいけません。組み込みの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);
}
1
Kemin Zhou

私はこれが非常に古い質問であることを知っています、しかし私はあなたのものに数行のコードを加えました、そしてそれは両端から空白を取り除きます。

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);
}
0
user3229557

c ++ 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

空の文字列でもうまく動作する

0
user1438233

下記は1パス(2パスかもしれません)の解決策です。文字列の空白部分を2回、空白以外の部分を1回超えます。

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;                                                                                                                                                                                                                               
}                                          
0
UnSat

これでいいの? (この投稿は完全に別の答えが必要です:)

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の場合も同じように、偏光子のインデックスを逆にします。

0
Bondolin

私はこれを使っています:

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);
}
0
Floella
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 );
}
0