C 从文件中读取矩阵,并带有多个定界符

C++ Read matrices from file with multiple delimiters

本文关键字:定界符 文件 读取      更新时间:2023-10-16

因此,我给了一个带有十个矩阵的文件,我想从文件中读取这些矩阵,然后将它们保存到向量/阵列中,每个矩阵都存储在vector中或一个向量或一个大批。但是,这些矩阵的格式使我很难阅读数据(我从输入文件中阅读不好)。

该文件具有以下格式。每个矩阵的元素被"分开。每一行被";"分开,每个矩阵都由" |"分开。例如,三个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
        }
    }

,但这显然很粗糙,只能通过逗号分开数据。有没有办法将数据与多个定界符分开?

谢谢!

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

我使用此功能将字符串拆分为字符串向量:

/**
 * 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);
    }
  }
}

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

这是您如何做到的概念。有关更多阅读,请在Internet上查看此内容。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;
}

您实际上已映射到非常简单的字节机。

从零矩阵开始,可以跟踪您正在编写的矩阵中的位置。一次阅读一个角色。如果字符是数字,则将矩阵中的当前数乘以10,然后将数字添加到其上,如果字符是逗号,请在该行中的下一个数字,如果字符是半彩色的下一行,如果字符是管道,请启动一个新矩阵。

如果数字是浮点,您可能不想这样做。我将它们保存在缓冲区中,并使用分析浮点数的标准方法。但是,除此之外,您实际上不需要保持太多复杂状态或建造大型解析器。您可能需要在以后的阶段添加错误处理,但是即使在那里,错误处理也很琐碎,并且仅取决于您扫描的当前字符。