关于矩阵:C ++从具有多个分隔符的文件中读取矩阵

C++ Read matrices from file with multiple delimiters

本问题已经有最佳答案,请猛点这里访问。

所以我得到了一个包含十个矩阵的文件,我想从文件中读取这些矩阵,并将它们保存到向量/数组中,每个矩阵都存储在向量或数组中。但是,这些矩阵的格式使我很难读取数据(我不擅长从输入文件中读取)。

文件的格式如下。每个矩阵的元素用","分隔。每一行用";"分隔,每一个矩阵用""分隔。例如,三个2乘2矩阵如下。

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

我只想把矩阵保存到三个不同的向量中,但我不知道该怎么做。

我试过

1
2
3
4
5
6
7
    while(getline(inFile,line)){
        stringstream linestream(line);
        string value;
        while(getline(linestream, value, ','){
               //save into vector
        }
    }

但这显然非常粗糙,只能用逗号分隔数据。有没有办法用多个分隔符来分隔数据?

谢谢您!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
 * \brief   Split a string in substrings
 * \param   sep  Symbol separating the parts
 * \param   str  String to be splitted
 *
eturn  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;
}

然后,期望你有一个类矩阵,你可以做如下的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
    }
  }
}

或者,压缩代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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);
    }
  }
}


您所拥有的示例实际上映射到一个非常简单的字节机。

从一个零矩阵开始,并跟踪你写的矩阵的位置。一次读一个字符。如果字符是数字,则将矩阵中的当前数字乘以10,然后将数字相加;如果字符是逗号,则前进到行中的下一个数字;如果字符是分号,则转到下一行;如果字符是管道,则启动新矩阵。

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


您可以使用finite state machine概念。您需要为每个步骤定义状态。读取一个字符,然后决定它是什么(数字或分隔符)。

以下是你如何做到这一点的概念。欲了解更多信息,请访问互联网。text parsingfinite state machinelexical analyzerformal grammar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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;
}