2017-05-03 11 views
1

要素のベクトルに数値の文字列を解析します。文字列は、() : /で区切られた4つの数字のブロックで構成され、各ブロックは;で区切られています。構造体のベクトルに数値の文字列を解析します。

具体的には、文字列の形式はint(int):float/float;です(下のコードサンプルを参照)。私は正規表現を使うことができると思っていますが、データが構造化されているので、そのような文字列を解析するためのより簡単で簡単な方法が必要です。私はistringstreamを使用していますが、それは少し不器用な感じです。

std::string line = "0(0):0/0;1(2):0.01/0.02;2(4):0.02/0.04;3(6):0.03/0.06;" 
struct Element { 
    int a; 
    int b; 
    int c; 
    int d; 
}; 

std::vector<Element> = parse(line); 


std::vector<Element> parse(std::string line) 
{ 
    std::vector<Element> elements; 
    std::istringstream iss(line); 
    while(iss) { 
    char dummy; 
    Element element; 

    iss >> element.a; 
    iss.read(&dummy,sizeof(dummy)); // (
    iss >> element.b; 
    iss.read(&dummy,sizeof(dummy)); //) 
    iss.read(&dummy,sizeof(dummy)); // : 
    iss >> element.c; 
    iss.read(&dummy,sizeof(dummy)); ///
    iss >> element.d; 
    iss.read(&dummy,sizeof(dummy)); // ; 

    if (!iss) {break;} 

    elements.push_back(element); 
    } 
    return elements; 
} 

私の質問:

  1. 解析するための良い方法だろうか? std::stringstreamを使用して番号で番号を読み取ってその間にある文字を「切り捨てる」べきですか?コードサンプルで行ったように?
  2. 最後の文字が読み込まれた後にwhile(iss)がまだtrueであるため、このコードにはバグがあり、追加の値を1つ読み込もうとします。iss>>の後にテストせずにこのループを終了するにはどうすればいいですか?またはより一般的には、抽出ストリームから抽出をループする方法は?
+2

'1 *のはsizeof(CHAR)' '式1 *のはsizeof(文字)1.'であることが保証され、値が '1'であるマジック'ダミー'と 'sizeof(char)'の文字数を参照していると思われる数字は 'ダミー'のタイプを参照しているようです。表現力や保守性のために定数1を指定しない場合は、単に 'sizeof(dummy)'を使用しないでください。現在のフォームは単に1を直接供給するよりも優れていません。 –

+0

文字列の形式を検証することは重要ですか、それとも正しいことがわかりますか?有効であることがわかっている場合は、数字以外の任意の文字列で文字列全体を単純にトークン化することができます。あなたは 'Element'を作るのが簡単な数字のリストを残しています。 [C++で文字列をどのようにトークン化するのですか?](http://stackoverflow.com/questions/53849/how-do-i-tokenize-a-string-in-c) –

+0

シリアライザについて考えたことはありますか?データ構造を読み取ることは、一般的な解決策に共通の問題です。 – Klaus

答えて

1

あなたのデータはよく構成されている、あなたは簡単にstd::ifstreamからクラスのメンバを抽出してistringstreamまたはファイル・ストリームからそれらを読み続けるためにoperator>>をオーバーロードすることができます。ここ

は可能な実装である:

#include <iostream> 
#include <vector> 
#include <string> 
#include <sstream> 
#include <fstream> 
#include <iterator> 
#include <stdexcept> 

class Element 
{ 
public: 
    Element() {} 
    Element(int aa, int bb, float cc, float dd) : a{aa}, b{bb}, c{cc}, d{dd} {} 

    friend std::istream &operator>> (std::istream &in, Element &e); 
    friend std::ostream &operator<< (std::ostream &out, Element const &e); 

private: 
    int a; 
    int b; 
    float c; 
    float d; 
}; 

std::istream &operator>> (std::istream &in, Element &e) 
{ 
    char delimiter; 
    if (not (in >> e.a >> delimiter and delimiter == '(' and 
       in >> e.b >> delimiter and delimiter == ')' and 
       in >> delimiter   and delimiter == ':' and 
       in >> e.c >> delimiter and delimiter == '/' and 
       in >> e.d >> delimiter and delimiter == ';') 
     and not in.eof()) 
    { 
     in.setstate(std::ios_base::failbit); 
    } 
    return in; 

} 

std::ostream &operator<< (std::ostream &out, Element const &e) 
{ 
    return out << e.a << '(' << e.b << "):" << e.c << '/' << e.d << ';'; 
} 

std::vector<Element> read_Elements_from(std::istream &in) 
{ 
    std::vector<Element> tmp (
     std::istream_iterator<Element>{in}, 
     std::istream_iterator<Element>{} 
    ); 
    if (not in.eof()) 
     throw std::runtime_error("Wrong format"); 

    return tmp; 
} 

int main() 
{ 
    try 
    { 
    using std::cout; 
    std::istringstream iss { 
     "0(0):0/0;1(2):0.01/0.2;2(4):0.02/0.04;3(6):0.03/0.06;" 
    }; 

    auto els_s = read_Elements_from(iss); 

    cout << "Elements read from the string:\n"; 
    for (auto const &i : els_s) 
    { 
     cout << i << '\n'; 
    } 

    // assuming a file which lines are similar to the string provided 
    std::ifstream input_file {"input_data.txt"}; 
    if (not input_file) 
     throw std::runtime_error("Can't open input file"); 

    auto els_f = read_Elements_from(input_file); 

    cout << "\nElements read from the file:\n"; 
    for (auto const &i : els_f) 
    { 
     cout << i << '\n'; 
    } 
    } 
    catch (std::exception const &e) 
    { 
     std::cerr << "\nAn unexpected problem cause this application to end:\n\n" 
       << e.what() << ".\n\n"; 
     return EXIT_FAILURE; 
    } 
} 
+0

非常にクール、例のために多くのおかげで。それはうまく動作し、完全に見える! –

関連する問題