2012-02-24 20 views
37

C++ 11を使用して文字列を分割する最も簡単な方法は何ですか?C++を使用して文字列を分割する11

これは、postで使用されているメソッドを見てきましたが、新しい標準を使用してそれを行う方法はあまり冗長でなければなりません。

編集結果:vector<string>を1文字に区切りたいと思います。

+1

分割?そして、私はC++ 11がここに何かを追加したとは思わないが、[受け入れられた答え](http://stackoverflow.com/a/237280/845092)は依然として最良の方法だと思う。 –

+0

分割後に何をしたいですか?プリントアウトするには?または部分文字列のベクトルを取得しますか? – balki

+0

これは正規表現解析の目的ではありませんか? –

答えて

4

これはあまり冗長ではありませんが、javascriptなどの動的言語で味付けした人にとってはgrokする方が簡単かもしれません。それが使用する唯一のC++ 11の機能はlambdaです。

#include <algorithm> 
#include <string> 
#include <cctype> 
#include <iostream> 
#include <vector> 

int main() 
{ 
    using namespace std; 
    string s = "hello how are you won't you tell me your name"; 
    vector<string> tokens; 
    string token; 

    for_each(s.begin(), s.end(), [&](char c) { 
    if (!isspace(c)) 
     token += c; 
    else 
    { 
     if (token.length()) tokens.push_back(token); 
     token.clear(); 
    } 
    }); 
    if (token.length()) tokens.push_back(token); 

    return 0; 
} 
+14

'for(auto const c:s){...}'はなぜですか? –

51

std::regex_token_iteratorは、正規表現に基づいて一般的なトークン化を実行します。これは、または単一の文字の上に簡単な分割を行うためには過剰であってもなくてもよいが、それは動作しますし、あまりにも冗長ではありません。

std::vector<std::string> split(const string& input, const string& regex) { 
    // passing -1 as the submatch index parameter performs splitting 
    std::regex re(regex); 
    std::sregex_token_iterator 
     first{input.begin(), input.end(), re, -1}, 
     last; 
    return {first, last}; 
} 
+24

素晴らしいアイデアは、読みにくいです。 –

+2

これはMSFTに固有のことです。 POSIXシステムには存在しません。 – jackyalcine

+0

[boost。](http://www.boost.org/doc/libs/1_56_0/libs/regex/doc/html/boost_regex/ref/regex_token_iterator.html)でも利用可能です。 – phs

4

私の選択はboost::tokenizerですが、私は巨大なデータを持つ任意の重い作業とテストを持っていませんでした。ラムダ修正とブーストドキュメントから 例:ここでは

#include <iostream> 
#include <boost/tokenizer.hpp> 
#include <string> 
#include <vector> 

int main() 
{ 
    using namespace std; 
    using namespace boost; 

    string s = "This is, a test"; 
    vector<string> v; 
    tokenizer<> tok(s); 
    for_each (tok.begin(), tok.end(), [&v](const string & s) { v.push_back(s); }); 
    // result 4 items: 1)This 2)is 3)a 4)test 
    return 0; 
} 
+2

なぜ範囲に基づいていないのですか? –

+5

C++ 11では、for(auto && s:tok){v.push_back(s);} } '。 –

3
#include <iostream> 
#include <algorithm> 
#include <vector> 
#include <string> 


using namespace std; 

vector<string> split(const string& str, int delimiter(int) = ::isspace){ 
    vector<string> result; 
    auto e=str.end(); 
    auto i=str.begin(); 
    while(i!=e){ 
    i=find_if_not(i,e, delimiter); 
    if(i==e) break; 
    auto j=find_if(i,e, delimiter); 
    result.push_back(string(i,j)); 
    i=j; 
    } 
    return result; 
} 

int main(){ 
    string line; 
    getline(cin,line); 
    vector<string> result = split(line); 
    for(auto s: result){ 
    cout<<s<<endl; 
    } 
} 
+0

なぜ 'int'を区切り文字として使用し、なぜ' int delimiter(int) 'を'(int) 'にするのでしょうか? – Ela782

+1

@ Ela782これは、関数ポインタ引数であり、intパラメータを受け取り、intを返す関数です。デフォルトはisspace関数です。 – Fsmv

13

は(あなたが言及したpostに基づく)は、文字列を分割する(多分それほど冗長)の方法です。

#include <string> 
#include <sstream> 
#include <vector> 
std::vector<std::string> split(const std::string &s, char delim) { 
    std::stringstream ss(s); 
    std::string item; 
    std::vector<std::string> elems; 
    while (std::getline(ss, item, delim)) { 
    elems.push_back(item); 
    // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson) 
    } 
    return elems; 
} 
+4

C++ 11を使用している場合は、ベクトルに挿入するときに文字列のコピーを避けるためにこれを行うこともできます。 elems.push_back(std :: move(item)); – mchiasson

2

これは私の答えです。冗長で読みやすく効率的です。

std::vector<std::string> tokenize(const std::string& s, char c) { 
    auto end = s.cend(); 
    auto start = end; 

    std::vector<std::string> v; 
    for(auto it = s.cbegin(); it != end; ++it) { 
     if(*it != c) { 
      if(start == end) 
       start = it; 
      continue; 
     } 
     if(start != end) { 
      v.emplace_back(start, it); 
      start = end; 
     } 
    } 
    if(start != end) 
     v.emplace_back(start, end); 
    return v; 
} 
+0

誰かがUTF8または複数の文字を使用したい場合を除きます。 – v010dya

+0

http://www.cplusplus.com/reference/cstring/strchr/ strchrの使用が許可されている場合は、実装に役立つことがあります。 – phoad

5

ここでは、文字列を分割し、抽出された要素をベクトルに埋め込む例をboostとしています。

#include <boost/algorithm/string.hpp> 

std::string my_input("A,B,EE"); 
std::vector<std::string> results; 

boost::algorithm::split(results, my_input, is_any_of(",")); 

assert(results[0] == "A"); 
assert(results[1] == "B"); 
assert(results[2] == "EE"); 
1

別の正規表現のソリューションinspired by other answersうまくいけば短く、簡単には読み:

ここ
std::string s{"String to split here, and here, and here,..."}; 
std::regex regex{R"([\s,]+)"}; // split on space and comma 
std::sregex_token_iterator it{s.begin(), s.end(), regex, -1}; 
std::vector<std::string> words{it, {}}; 
1

を見つける::だけのstd ::文字列を使用してC++ 11のソリューションです()。区切り文字は任意の長さの文字にすることができます。解析されたトークンは出力イテレータを介して出力されます。これは通常、自分のコードのstd :: back_inserterです。

私はこれをUTF-8でテストしていませんが、入力と区切り文字が両方とも有効なUTF-8文字列であれば動作するはずです。

#include <string> 

template<class Iter> 
Iter splitStrings(const std::string &s, const std::string &delim, Iter out) 
{ 
    if (delim.empty()) { 
     *out++ = s; 
     return out; 
    } 
    size_t a = 0, b = s.find(delim); 
    for (; b != std::string::npos; 
      a = b + delim.length(), b = s.find(delim, a)) 
    { 
     *out++ = std::move(s.substr(a, b - a)); 
    } 
    *out++ = std::move(s.substr(a, s.length() - a)); 
    return out; 
} 

いくつかのテストケース:

void test() 
{ 
    std::vector<std::string> out; 
    size_t counter; 

    std::cout << "Empty input:" << std::endl;   
    out.clear(); 
    splitStrings("", ",", std::back_inserter(out)); 
    counter = 0;   
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) { 
     std::cout << counter << ": " << *i << std::endl; 
    } 

    std::cout << "Non-empty input, empty delimiter:" << std::endl;   
    out.clear(); 
    splitStrings("Hello, world!", "", std::back_inserter(out)); 
    counter = 0;   
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) { 
     std::cout << counter << ": " << *i << std::endl; 
    } 

    std::cout << "Non-empty input, non-empty delimiter" 
       ", no delimiter in string:" << std::endl;   
    out.clear(); 
    splitStrings("abxycdxyxydefxya", "xyz", std::back_inserter(out)); 
    counter = 0;   
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) { 
     std::cout << counter << ": " << *i << std::endl; 
    } 

    std::cout << "Non-empty input, non-empty delimiter" 
       ", delimiter exists string:" << std::endl;   
    out.clear(); 
    splitStrings("abxycdxy!!xydefxya", "xy", std::back_inserter(out)); 
    counter = 0;   
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) { 
     std::cout << counter << ": " << *i << std::endl; 
    } 

    std::cout << "Non-empty input, non-empty delimiter" 
       ", delimiter exists string" 
       ", input contains blank token:" << std::endl;   
    out.clear(); 
    splitStrings("abxycdxyxydefxya", "xy", std::back_inserter(out)); 
    counter = 0;   
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) { 
     std::cout << counter << ": " << *i << std::endl; 
    } 

    std::cout << "Non-empty input, non-empty delimiter" 
       ", delimiter exists string" 
       ", nothing after last delimiter:" << std::endl;   
    out.clear(); 
    splitStrings("abxycdxyxydefxy", "xy", std::back_inserter(out)); 
    counter = 0;   
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) { 
     std::cout << counter << ": " << *i << std::endl; 
    } 

    std::cout << "Non-empty input, non-empty delimiter" 
       ", only delimiter exists string:" << std::endl;   
    out.clear(); 
    splitStrings("xy", "xy", std::back_inserter(out)); 
    counter = 0;   
    for (auto i = out.begin(); i != out.end(); ++i, ++counter) { 
     std::cout << counter << ": " << *i << std::endl; 
    } 
} 

予想される出力:スペース上の

 
Empty input: 
0: 
Non-empty input, empty delimiter: 
0: Hello, world! 
Non-empty input, non-empty delimiter, no delimiter in string: 
0: abxycdxyxydefxya 
Non-empty input, non-empty delimiter, delimiter exists string: 
0: ab 
1: cd 
2: !! 
3: def 
4: a 
Non-empty input, non-empty delimiter, delimiter exists string, input contains blank token: 
0: ab 
1: cd 
2: 
3: def 
4: a 
Non-empty input, non-empty delimiter, delimiter exists string, nothing after last delimiter: 
0: ab 
1: cd 
2: 
3: def 
4: 
Non-empty input, non-empty delimiter, only delimiter exists string: 
0: 
1: 
関連する問題