2017-02-23 108 views
5

因此,我給出了一個包含十個矩陣的文件,我想從文件中讀取這些矩陣,並將它們保存到向量/數組中,其中每個矩陣存儲到向量或陣列。但是,這些矩陣的格式使我很難讀取數據(我不擅長從輸入文件中讀取數據)。C++從帶有多個分隔符的文件中讀取矩陣

該文件具有以下格式。每個矩陣的元素由「,」分隔。每行由「;」分隔,每個矩陣由「|」分隔。例如,三個2乘2矩陣如下。

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

而我只是想將矩陣保存到三個不同的向量,但我不知道如何做到這一點。

我試圖

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

但是,這顯然是非常粗糙的,只有逗號的方式隔開數據。有沒有辦法用多個分隔符分隔數據?

謝謝!

回答

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概念。您需要爲每個步驟定義狀態。 讀取一個字符,然後決定它是什麼(數字或分隔符)。

這裏是你如何做到這一點的概念。 更多的閱讀材料請在互聯網上。 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

您實際上已經映射到一個非常簡單的字節機的例子。

從一個歸零矩陣開始,它跟蹤你正在寫的矩陣中的哪個位置。一次讀一個角色。如果字符是數字,則將矩陣中的當前數字乘以10並將其添加到數字,如果該字符是逗號,則前進到該行中的下一個數字,如果該字符是分號,則轉到下一行,如果該字符是管道,則啓動一個新的矩陣。

如果數字是浮點數,你可能不想這樣做。我將它們保存在一個緩衝區中,並使用解析浮點數的標準方法。但除此之外,你並不需要保持複雜的狀態或構建一個大的解析器。您可能希望在稍後階段添加錯誤處理,但即使在那裏,錯誤處理也非常簡單,只取決於您正在掃描的當前字符。

相關問題