web-dev-qa-db-ja.com

文字列から空白を削除

JavaとCのニースでこれを行う方法はいくつかありますが、C++では、文字列トリミング関数を簡単に実装する方法を見つけることができないようです。

これは私が現在持っているものです:

string trim(string& str)
{
    size_t first = str.find_first_not_of(' ');
    size_t last = str.find_last_not_of(' ');
    return str.substr(first, (last-first+1));
}

しかし、私が電話しようとするたびに

trim(myString);

コンパイラエラーが表示されます

/tmp/ccZZKSEq.o: In function `song::Read(std::basic_ifstream<char, 
std::char_traits<char> >&, std::basic_ifstream<char, std::char_traits<char> >&, char const*, char const*)':
song.cpp:(.text+0x31c): undefined reference to `song::trim(std::string&)'
collect2: error: ld returned 1 exit status

私は100行のコードを使わずに文字列から先頭と末尾の空白をトリミングする簡単で標準的な方法を見つけようとしています。正規表現を使用しようとしましたが、それもうまくいきませんでした。

Boostも使用できません。

19
follmer

コードは問題ありません。表示されているのは、リンカーの問題です。

コードを次のような単一のファイルに入れる場合:

#include <iostream>
#include <string>

using namespace std;

string trim(const string& str)
{
    size_t first = str.find_first_not_of(' ');
    if (string::npos == first)
    {
        return str;
    }
    size_t last = str.find_last_not_of(' ');
    return str.substr(first, (last - first + 1));
}

int main() {
    string s = "abc ";
    cout << trim(s);

}

その後、g++ test.ccとa.outを実行すると、動作することがわかります。

trim関数を含むファイルがコンパイルプロセスのリンクステージに含まれているかどうかを確認する必要があります。

38
Anthony Kong

方法は次のとおりです。

std::string & trim(std::string & str)
{
   return ltrim(rtrim(str));
}

また、サポート機能は次のように実装されます。

std::string & ltrim(std::string & str)
{
  auto it2 =  std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( str.begin() , it2);
  return str;   
}

std::string & rtrim(std::string & str)
{
  auto it1 =  std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( it1.base() , str.end() );
  return str;   
}

そして、これらをすべて設定したら、次のように書くこともできます。

std::string trim_copy(std::string const & str)
{
   auto s = str;
   return ltrim(rtrim(s));
}

これを試して

22
gjha

Strが空白のみを含む場合、substr()は例外をスローすると思います。

次のコードに変更します。

string trim(string& str)
{
    size_t first = str.find_first_not_of(' ');
    if (first == std::string::npos)
        return "";
    size_t last = str.find_last_not_of(' ');
    return str.substr(first, (last-first+1));
}
6
Martin

@gjhaの回答に加えて:

inline std::string ltrim_copy(const std::string& str)
{
    auto it = std::find_if(str.cbegin(), str.cend(),
        [](char ch) { return !std::isspace<char>(ch, std::locale::classic()); });
    return std::string(it, str.cend());
}

inline std::string rtrim_copy(const std::string& str)
{
    auto it = std::find_if(str.crbegin(), str.crend(),
        [](char ch) { return !std::isspace<char>(ch, std::locale::classic()); });
    return it == str.crend() ? std::string() : std::string(str.cbegin(), ++it.base());
}

inline std::string trim_copy(const std::string& str)
{
    auto it1 = std::find_if(str.cbegin(), str.cend(),
        [](char ch) { return !std::isspace<char>(ch, std::locale::classic()); });
    if (it1 == str.cend()) {
        return std::string();
    }
    auto it2 = std::find_if(str.crbegin(), str.crend(),
        [](char ch) { return !std::isspace<char>(ch, std::locale::classic()); });
    return it2 == str.crend() ? std::string(it1, str.cend()) : std::string(it1, ++it2.base());
}
0
ivan.ukr
#include <vector>
#include <numeric>
#include <sstream>
#include <iterator>

void Trim(std::string& inputString)
{
    std::istringstream stringStream(inputString);
    std::vector<std::string> tokens((std::istream_iterator<std::string>(stringStream)), std::istream_iterator<std::string>());

    inputString = std::accumulate(std::next(tokens.begin()), tokens.end(),
                                 tokens[0], // start with first element
                                 [](std::string a, std::string b) { return a + " " + b; });
}
0
Will