2017-02-23 107 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并将其添加到数字,如果该字符是逗号,则前进到该行中的下一个数字,如果该字符是分号,则转到下一行,如果该字符是管道,则启动一个新的矩阵。

如果数字是浮点数,你可能不想这样做。我将它们保存在一个缓冲区中,并使用解析浮点数的标准方法。但除此之外,你并不需要保持复杂的状态或构建一个大的解析器。您可能希望在稍后阶段添加错误处理,但即使在那里,错误处理也非常简单,只取决于您正在扫描的当前字符。

相关问题