バイナリ文字列(std::vector<unsigned char>)と数字配列(std::vector<int>)を引数にとり、CSV形式の文字列で返す関数及びクラスの実装を教えてください。
関数のシグネチャは下記のような感じを想定しています。
// 必要な関数
std::string func(
const std::vector<unsigned char>& data,
const std::vector<int>& separate);
// 利用イメージ
int main()
{
const std::vector<unsigned char> data = {0x31,0x32,0x33,0x34,0x35,0x36};
const set::vector<int> separate = {1,2,2,1};
std::string str = func(data,separate);
std::cout << str; // 出力 1,23,45,6
retrun 0;
}
前提:
・バイト列はASCII範囲とします。
・C++03ですが、C++11で回答いただいてもこちらで書き直します。
・単純にforやifばかりの複雑度の高い処理でなくalgorithmなどのSTLを利用してください。
for文とif文でネストすれば実装できるのですが、algorithmを利用した実装方法を教えてください。
追記
下のような関数を考えてみました。結局algorithmはつかっていません。
下記の点で問題があるかと思います。
・insertの度に移動の計算が走る
・indexの加算をoperator++ でなく数値で加算しているので領域外参照する恐れがある
・774RR 様のご指摘の通りif文で細かな条件チェックをしてしまっているのでそこで複雑度が増加してしまう。
これらをalgorithmを利用してスマートに解決できればとおもい質問させていただきました。
std::string StringToCsv(std::string &data, std::vector<int>& seperater)
{
// 元のデータ長+カンマの数で領域を確保
std::string str = data;
str.reserve(data.size() + seperater.size());
// カンマを挿入する
typedef std::vector<int>::iterator VecIt;
VecIt comma_index = seperater.begin();
const VecIt end = seperater.end();
std::string::iterator itr = str.begin();
while (comma_index != end)
{
itr += *comma_index;
// はみ出たらその場で終了する。
if (itr >= str.end()) { break; }
itr = str.insert(itr, ',');
++comma_index;
++itr;
}
// 最後のカンマを消す
if (*(itr - 1) == ',')
{
str.replace(itr - 1, itr, "");
}
std::cout << str;
return str;
}
int main()
{
//test_csvParser();
std::vector<int> sep = { 1,2,3,1,1,5}; // 0,1,3,6,7,8
std::string data = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38 };
StringToCsv(data, sep);
}