0

文字列「SplitAtSpaces」を、「Split」「At」「Spaces」を含むベクトルに分割する関数を作成しようとしています。これまでのところ、これは私が持っているコードです。

#include <iostream>
#include <utility>
#include <algorithm>

using namespace std;

std::vector<std::string> split(std::string * s, char * tosplit) 
{
    size_t i = 0;
    int count = 0;
    size_t contain;
    std::vector<std::string> split;

    std::cout << "Start" << std::endl;
    std::cout << *s << std::endl;
    std::cout << *tosplit << std::endl;

    while((contain = s->find(*tosplit,i)) != std::string::npos)
    {
        count++;
        i = contain + 1;
    }

    std::cout << "Contains " << count << std::endl;

    if (count == 0)
    {
        std::cout << "Equals 0" << std::endl;
        split = std::vector<std::string>(1);
        split.at(0) = s->c_str();
        return split;
    }

    split = std::vector<std::string>(count + 1);
    split.begin();

    int lasti;
    i = s->find_first_of(*tosplit);
    split.at(0) = s->substr(0, i);
    lasti = i;
    int runs = 1;

    while (runs <= count) 
    {
        i = s->find(*tosplit, lasti + 1);
        std::cout << i << " " << lasti << std::endl;
        split.at(runs) = s->substr(lasti, --i);
        runs++;
        lasti = i;
    }

    split.at(runs) = s->substr(lasti, s->size());

    std::cout << "done, result is" << std::endl;
    i = 0;
    while (i < split.capacity()) 
    {
        std::cout << split.at(i) << std::endl;
        i++;
    }

    return split;
}

out_of_range例外をスローします。あなたが与えることができるどんな助けでもありがたいです。これは、関数でポインターを使用する最初の部分のようなものなので、ここでちょっと推測しています。
ありがとう!

xまたはyメソッドの使用を提案しないでください。私は経験のためにそれを行っているので、私は自分で書きたいと思います。

4

5 に答える 5

1

ここに私が見つけたいくつかの問題があります:

  1. sNULL ポインターをチェックする前の逆参照。
  2. tosplitNULL をチェックする前の逆参照。
  3. 文字列の数をカウントしてから文字列を分割する (2 回の検索が必要) 代わりに、検索しながらカウントします。
  4. ループ内の式に渡すと、位置i = contain + 1が範囲外になる場合があります。while
  5. std::vector::push_back特定の、おそらく割り当てられていない位置に割り当てるのではなく、メソッドを使用してみてください。
  6. このステートメントreturn splitは、文字列の配列のコピーを返します。本当に大きなデータ構造を返したいですか?
  7. このステートメントsplit.begin()は、ベクトルの先頭への反復子を返します。使用しないもの。
  8. 使用しsplit.size()ないでくださいsplit.capacity。これらは 2 つの異なる概念です。
于 2013-02-01T22:02:20.927 に答える
1

これは、標準イテレータ ライブラリの助けを借りて、 egstd::istringstreamとを使用すると実際に簡単に実行できます。std::copy

実際のコードを見たい人は、ここで見つけることができます。

リンクのコードでは、プログラム全体が 18 行で、実際の分割は 3 行ですが、これは読みやすくするために分割したためです (実際には 1 つの関数呼び出しです)。


より一般的な解決策として、C++11正規表現が利用可能な場合 (またはBoost regex、または他の正規表現ライブラリが利用可能な場合) に使用できます。

于 2013-02-01T21:47:09.167 に答える
0

単一区切り文字:

これを行うには、あまりにも多くのコードを書きすぎました。数行でできます。あなたは非常に複雑になっています。そして、このためにポインターで実際に何かをする理由はありません。

vector<string> Split(string s, char delim)
{
    vector<string> strings;
    for(istringstream ss(s); getline(ss, s, delim); strings.push_back(move(s)));
    return strings;
}

複数の区切り記号:

複数の区切り文字を使用するためのソリューションは、より複雑です。を活用することはできなくなりましgetlineた。つまり、基本的にgetlineの機能の一部を自分で作成していることになります。それでも、かなり短くなる可能性があります。

vector<string> Split(const string& s, const char* delims)
{
    vector<string> strings;

    for(string::size_type start = 0, end; end != string::npos && start < s.size(); start = end+1)
    {
        end = s.find_first_of(delims, start);
        strings.push_back(s.substr(start, end-start));
    }

    return strings;
}

これにより、区切り文字が隣り合っている場合に空白文字列が追加されます。push_backそれが隣接する区切り文字の望ましい動作でない場合は、 with をガードすることで簡単に回避できますif(start != end)

結論:

このような低レベルのアルゴリズムを書き始めるときは、大まかに疑似コードを作成してから、コードを書く前に、作業の一部またはすべてを切り取るために C++ 標準ライブラリが提供できるものを確認してください。より小さく、エラーが発生しにくく、より理解しやすいコードになります。find_first_ofたとえば、手巻きの実装を見たいと思う人は誰もいません。言葉を読む方がはるかに明確find_first_ofです。その関数が何をするのかは明らかであり、バグがないことも (願わくば) 明らかです。

于 2013-02-01T22:23:29.883 に答える
0

ベクターのスペースを事前に割り当てようとする代わりに、push_back を使用してパーツを見つけたら追加します。

于 2013-02-01T21:47:14.217 に答える
0

申し訳ありませんが、あなたの機能は複雑すぎると思わざるを得ません。事前にパックされた機能を使用するのではなく、学習のために自分でロジックをコーディングしたい場合は問題ありませんが、これはロジックをシンプルに保つべきではないという意味ではありません。

アルゴリズムは次のようになるはずです。

// Note that the delimiter can be a string as well, not just a char
vector<string> split(string const& s, string const& delimiter)
{
    vector<string> result;

    string::size_type startPos = 0;
    string::size_typepos = s.find(delimiter);
    while (pos != string::npos)
    {
        // Extract token and save it...
        string token = s.substr(startPos, pos - startPos);
        result.push_back(token);

        // Step to next token...
        startPos = pos + 1;
        pos = s.find(delimiter, pos + 1);
    }

    // Parse last token (in case the string is not terminated
    // by the delimiter).
    if (startPos < s.length())
    {
        string lastToken = s.substr(startPos);
        result.push_back(lastToken);
    }

    return result;
}
于 2013-02-01T21:48:57.853 に答える