web-dev-qa-db-ja.com

複数の区切り文字で文字列を単語に分割します

テキスト(意味のあるテキストまたは算術式)があり、それを単語に分割したい。
単一の区切り文字がある場合、次を使用します。

std::stringstream stringStream(inputString);
std::string Word;
while(std::getline(stringStream, Word, delimiter)) 
{
    wordVector.Push_back(Word);
}

文字列をいくつかの区切り文字でトークンに分割するにはどうすればよいですか?

30
wzxsvm

区切り文字の1つが改行であると仮定すると、次の行は行を読み取り、区切り文字でさらに分割します。この例では、区切り文字スペース、アポストロフィ、およびセミコロンを選択しました。

std::stringstream stringStream(inputString);
std::string line;
while(std::getline(stringStream, line)) 
{
    std::size_t prev = 0, pos;
    while ((pos = line.find_first_of(" ';", prev)) != std::string::npos)
    {
        if (pos > prev)
            wordVector.Push_back(line.substr(prev, pos-prev));
        prev = pos+1;
    }
    if (prev < line.length())
        wordVector.Push_back(line.substr(prev, std::string::npos));
}
42
SoapBox

ブーストがある場合は、次を使用できます。

#include <boost/algorithm/string.hpp>
std::string inputString("One!Two,Three:Four");
std::string delimiters("|,:");
std::vector<std::string> parts;
boost::split(parts, inputString, boost::is_any_of(delimiters));
18
Matthew Smith

手動の方法を誰も指摘しなかった理由はわかりませんが、ここにあります:

const std::string delims(";,:. \n\t");
inline bool isDelim(char c) {
    for (int i = 0; i < delims.size(); ++i)
        if (delims[i] == c)
            return true;
    return false;
}

および機能:

std::stringstream stringStream(inputString);
std::string Word; char c;

while (stringStream) {
    Word.clear();

    // Read Word
    while (!isDelim((c = stringStream.get()))) 
        Word.Push_back(c);
    if (c != EOF)
        stringStream.unget();

    wordVector.Push_back(Word);

    // Read delims
    while (isDelim((c = stringStream.get())));
    if (c != EOF)
        stringStream.unget();
}

この方法で、必要に応じてdelimsで何か便利なことができます。

4
forumulator

ブーストを使用せずに自分で行う方法に興味がある場合。

区切り文字列が非常に長いと仮定します-文字列のすべての文字が区切り文字であるかどうかをチェックするMを言うと、コストO(M)それぞれなので、ループでそうします元の文字列のすべての文字、たとえば長さNの場合、O(M * N)です。

ディクショナリを使用します(マップ-「区切り文字」から「ブール値」のように-ここでは、各区切り文字のindex = ascii値がtrueである単純なブール配列を使用します)。

文字列を繰り返し処理し、charが区切り文字であるかどうかをO(1)でチェックします。これにより、最終的にO(N)全体が得られます。

これが私のサンプルコードです。

const int dictSize = 256;    

vector<string> tokenizeMyString(const string &s, const string &del)
{
    static bool dict[dictSize] = { false};

    vector<string> res;
    for (int i = 0; i < del.size(); ++i) {      
        dict[del[i]] = true;
    }

    string token("");
    for (auto &i : s) {
        if (dict[i]) {
            if (!token.empty()) {
                res.Push_back(token);
                token.clear();
            }           
        }
        else {
            token += i;
        }
    }
    if (!token.empty()) {
        res.Push_back(token);
    }
    return res;
}


int main()
{
    string delString = "MyDog:Odie, MyCat:Garfield  MyNumber:1001001";
//the delimiters are " " (space) and "," (comma) 
    vector<string> res = tokenizeMyString(delString, " ,");

    for (auto &i : res) {

        cout << "token: " << i << endl;
    }
return 0;
}

注:tokenizeMyStringは値によってベクトルを返し、最初にスタック上に作成するため、ここではコンパイラーの力を使用しています>>> RVO-戻り値の最適化:)

0
Kohn1001