2017-02-23 12 views
5

ファイルが10個ありますので、これらの行列をファイルから読み込んでベクトル/配列に保存したいと思います。アレイ。しかし、これらの行列の形式は、私がデータを読みにくくしています(私は入力ファイルから読み込むのは良くありません)。C++複数の区切り文字を含むファイルから行列を読み込みます

ファイルの形式は次のとおりです。各行列の要素は "、"で区切られています。各行は「;」で区切られ、各行列は「|」で区切られています。例えば、3つの2×2行列は、以下の通りである。

1,2,3,4 | 0,1; 1,0 | 5,3; 3,1 |

そして、行列を3つの異なるベクトルに保存したいだけですが、どうすればよいか分かりません。

私は

while(getline(inFile,line)){ 
     stringstream linestream(line); 
     string value; 
     while(getline(linestream, value, ','){ 
       //save into vector 
     } 
    } 

を試してみました。しかし、これは明らかに非常に、粗である、とだけコンマでデータをseperates。複数の区切り文字でデータを区切る方法はありますか?

ありがとうございました!

答えて

6
string line; 
while(getline(infile, line, '|')) 
{ 
    stringstream rowstream(line); 
    string row; 
    while(getline(rowstream, row, ';')) 
    { 
      stringstream elementstream(row); 
      string element; 
      while(getline(elementstream, element, ',')) 
      { 
       cout << element << endl;      
      } 
    } 
} 

は、コードの上に使用して、あなたが好きなように、個々のelementを保存するためのロジックを構築することができます。

1

finite state machineのコンセプトを使用できます。各ステップの状態を定義する必要があります。 1つのcharを読み取り、それが何であるか(番号または区切り文字)を決定します。

ここにあなたがそれを行う方法の概念があります。 詳しくは、インターネットで確認してください。 text parsingfinite state machinelexical analyzerformal grammar

enum State 
{ 
    DECIMAL_NUMBER, 
    COMMA_D, 
    SEMICOLON_D, 
    PIPE_D, 
    ERROR_STATE, 
}; 

char GetChar() 
{ 
    // implement proper reading from file 
    static char* input = "1,2;3,4|0,1;1,0|5,3;3,1|"; 
    static int index = 0; 

    return input[index++]; 
} 

State GetState(char c) 
{ 
    if (isdigit(c)) 
    { 
     return DECIMAL_NUMBER; 
    } 
    else if (c == ',') 
    { 
     return COMMA_D; 
    } 
    else if (c == ';') 
    { 
     return SEMICOLON_D; 
    } 
    else if (c == '|') 
    { 
     return PIPE_D; 
    } 

    return ERROR_STATE; 
} 

int main(char* argv[], int argc) 
{ 
    char c; 
    while (c = GetChar()) 
    { 
     State s = GetState(c); 
     switch (c) 
     { 
     case DECIMAL_NUMBER: 
      // read numbers 
      break; 
     case COMMA_D: 
      // append into row 
      break; 
     case SEMICOLON_D: 
      // next row 
      break; 
     case PIPE_D: 
      // finish one matrix 
      break; 
     case ERROR_STATE: 
      // syntax error 
      break; 
     default: 
      break; 
     } 
    } 
    return 0; 
} 
2

私は文字列のベクトルに文字列を分割するために、この独自の機能を使用します。

/** 
* \brief Split a string in substrings 
* \param sep Symbol separating the parts 
* \param str String to be splitted 
* \return Vector containing the splitted parts 
* \pre  The separator can not be 0 
* \details Example : 
* \code 
* std::string str = "abc.def.ghi..jkl."; 
* std::vector<std::string> split_str = split('.', str); // the vector is ["abc", "def", "ghi", "", "jkl", ""] 
* \endcode 
*/ 
std::vector<std::string> split(char sep, const std::string& str); 

std::vector<std::string> split(char sep, const std::string& str) 
{ 
    assert(sep != 0 && "PRE: the separator is null"); 
    std::vector<std::string> s; 
    unsigned long int i = 0; 
    for(unsigned long int j = 0; j < str.length(); ++j) 
    { 
    if(str[j] == sep) 
    { 
     s.push_back(str.substr(i, j - i)); 
     i = j + 1; 
    } 
    } 
    s.push_back(str.substr(i, str.size() - i)); 
    return s; 
} 

その後、あなたはクラスのマトリックスを持って期待して、あなたのような何かを行うことができます:

std::string matrices_str; 
std::ifstream matrix_file(matrix_file_name.c_str()); 
matrix_file >> matrices_str; 
const std::vector<std::string> matrices = split('|', matrices_str); 
std::vector<Matrix<double> > M(matrices.size()); 
for(unsigned long int i = 0; i < matrices.size(); ++i) 
{ 
    const std::string& matrix = matrices[i]; 
    const std::vector<std::string> rows = split(';', matrix); 
    for(unsigned long int j = 0; j < rows.size(); ++j) 
    { 
    const std::string& row = matrix[i]; 
    const std::vector<std::string> elements = split(',', row); 
    for(unsigned long int k = 0; k < elements.size(); ++k) 
    { 
     const std::string& element = elements[k]; 
     if(j == 0 && k == 0) 
     M[i].resize(rows.size(), elements.size()); 
     std::istringstream iss(element); 
     iss >> M[i](j,k); 
    } 
    } 
} 

あるいは、圧縮コード:

std::string matrices_str; 
std::ifstream matrix_file(matrix_file_name.c_str()); 
matrix_file >> matrices_str; 
const std::vector<std::string> matrices = split('|', matrices_str); 
std::vector<Matrix<double> > M(matrices.size()); 
for(unsigned long int i = 0; i < matrices.size(); ++i) 
{ 
    const std::vector<std::string> rows = split(';', matrices[i]); 
    for(unsigned long int j = 0; j < rows.size(); ++j) 
    { 
    const std::vector<std::string> elements = split(',', matrix[i]); 
    for(unsigned long int k = 0; k < elements.size(); ++k) 
    { 
     if(j == 0 && k == 0) 
     M[i].resize(rows.size(), elements[k].size()); 
     std::istringstream iss(elements[k]); 
     iss >> M[i](j,k); 
    } 
    } 
} 
1

この例は、実際には非常に単純なバイトマシンにマップされています。

ゼロ行列と、あなたが書いている行列のどこを追跡しているかで始まります。一度に1文字ずつ読む。文字が数字の場合は、行列の現在の数値に10を掛けて数字を加算し、文字がカンマの場合は行の次の数字に進み、文字がセミコロンの場合は次の行、文字がパイプの場合は、新しい行列を開始します。

数値が浮動小数点の場合は、このように正確に行う必要はありません。私はそれらをバッファに保存し、浮動小数点数を解析する標準的な方法を使用します。しかしそれ以外には、複雑な状態を維持したり、大きなパーサを構築する必要はありません。後の段階でエラー処理を追加したいかもしれませんが、エラー処理は非常に簡単で、スキャンしている現在の文字だけに依存します。

関連する問題