4

CSVファイルを1行ずつ読み取る機能があります。ラインごとに、ラインをベクトルに分割します。これを行うコードは

    std::stringstream ss(sText);
    std::string item;

    while(std::getline(ss, item, ','))
    {
        m_vecFields.push_back(item);
    }

最後の値が空白の行を読み取る場合を除いて、これは正常に機能します。例えば、

text1,tex2,

3 番目の値が空であるサイズ 3 のベクトルを返すようにします。ただし、代わりにサイズ 2 のベクトルを返すだけです。これを修正するにはどうすればよいですか?

4

5 に答える 5

4

boost::splitこれをすべて行うために使用できます。
http://www.boost.org/doc/libs/1_50_0/doc/html/string_algo/usage.html#id3207193

必要な動作が 1 行で行われます。

boost::split コードの例

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

using namespace std;

int main()
{
    vector<string> strs;

    boost::split(strs, "please split,this,csv,,line,", boost::is_any_of(","));

    for ( vector<string>::iterator it = strs.begin(); it < strs.end(); it++ )
        cout << "\"" << *it << "\"" << endl;

    return 0;
}

結果

"please split"
"this"
"csv"
""
"line"
""
于 2012-07-03T13:52:32.717 に答える
2

次のような関数を使用できます。

template <class InIt, class OutIt>
void Split(InIt begin, InIt end, OutIt splits)
{
    InIt current = begin;
    while (begin != end)
    {
        if (*begin == ',')
        {
            *splits++ = std::string(current,begin);
            current = ++begin;
        }
        else
            ++begin;
    }
    *splits++ = std::string(current,begin);
}

文字列を反復処理し、区切り文字に遭遇すると、文字列を抽出して分割イテレータに格納します。
興味深い部分は

  • current == beginの場合、空の文字列が挿入されます(テストケース: "text1 ,, tex2")
  • 最後の挿入により、常に正しい数の要素が存在することが保証されます。
    末尾にコンマがある場合は、前の箇条書きをトリガーして空の文字列を追加します。それ以外の場合は、最後の要素をベクトルに追加します。

次のように使用できます。

std::stringstream ss(sText);
std::string item;
std::vector<std::string> m_vecFields;
while(std::getline(ss, item))
{
    Split(item.begin(), item.end(), std::back_inserter(m_vecFields));
}

std::for_each(m_vecFields.begin(), m_vecFields.end(), [](std::string& value)
{
    std::cout << value << std::endl;
});
于 2012-07-03T13:32:21.057 に答える
2

C++11 では、 regex_token_iteratorを使用して、エスケープされたコンマも非常に簡単に処理できます。

std::stringstream ss(sText);
std::string item;
const regex re{"((?:[^\\\\,]|\\\\.)*?)(?:,|$)"};

std::getline(ss, item)

m_vecFields.insert(m_vecFields.end(), sregex_token_iterator(item.begin(), item.end(), re, 1), sregex_token_iterator());

vector<string>ちなみに、次のように CSV から単純に を作成したい場合は、次のstringようにしitemます。

const regex re{"((?:[^\\\\,]|\\\\.)*?)(?:,|$)"};
vector<string> m_vecFields{sregex_token_iterator(item.begin(), item.end(), re, 1), sregex_token_iterator()};

実例

の簡単な説明regexがおそらく適切です。(?:[^\\\\,]|\\\\.)エスケープ文字または非','文字に一致します。(詳細については、こちらを参照してください: https://stackoverflow.com/a/7902016/2642059 )*?貪欲な一致ではないことを意味するため、最初 ','に到達したところで停止します。キャプチャにネストされているものはすべて、最後のパラメーターである1, toによって選択されますregex_token_iterator。最後に、 -delimiter または . の末尾に(?:,|$)一致します。','string

この標準の CSV リーダーが空の要素を無視するようにするには、複数の文字を含む文字列のみに一致するように正規表現を変更できます。

const regex re{"((?:[^\\\\,]|\\\\.)+?)(?:,|$)"};

1 つ以上の一致する文字が必要であることを示す'+'が置き換えられたことに注意してください。これにより、で終わる文字列と'*'一致しなくなります。この例をここで見ることができます: http://ideone.com/W4n44Witem','

于 2015-03-05T14:45:55.680 に答える
2

csv ファイルを解析するための柔軟なソリューション: ここで:

source - CSV ファイルの内容

区切り文字 - CSV 区切り文字など。',' ';'

std::vector<std::string> csv_split(std::string source, char delimeter) {
    std::vector<std::string> ret;
    std::string word = "";
    int start = 0;

    bool inQuote = false;
    for(int i=0; i<source.size(); ++i){
        if(inQuote == false && source[i] == '"'){
            inQuote = true;
            continue;
        }
        if(inQuote == true && source[i] == '"'){
            if(source.size() > i && source[i+1] == '"'){
                ++i;
            } else {
                inQuote = false;
                continue;
            }
        }

        if(inQuote == false && source[i] == delimeter){
            ret.push_back(word);
            word = "";
        } else {
            word += source[i];
        }
    }
    ret.push_back(word);

    return ret;
}
于 2015-03-22T16:17:39.910 に答える
2
bool addEmptyLine = sText.back() == ',';

/* your code here */

if (addEmptyLine) m_vecFields.push_back("");

また

sText += ',';     // text1, text2,,

/* your code */

assert(m_vecFields.size() == 3);
于 2012-07-03T13:00:11.843 に答える