【问题标题】:C++ Read matrices from file with multiple delimiters [duplicate]C ++从具有多个分隔符的文件中读取矩阵[重复]
【发布时间】:2017-07-13 13:59:58
【问题描述】:

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

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

但这显然是非常粗略的,并且只用逗号分隔数据。有没有办法用多个分隔符分隔数据?

谢谢!

【问题讨论】:

    标签: c++ matrix


    【解决方案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;
      }
      

      然后,期望您有一个类 Matrix,您可以执行以下操作:

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

      【讨论】:

        【解决方案3】:
        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

        【讨论】:

          【解决方案4】:

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

          从一个归零的矩阵开始,以及跟踪你正在编写的矩阵中的位置的东西。一次读一个字符。如果字符是数字,则将矩阵中的当前数字乘以 10 并添加数字,如果字符是逗号,则前进到行中的下一个数字,如果字符是分号,转到下一行,如果字符是管道,则开始一个新矩阵。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-05
            • 1970-01-01
            • 1970-01-01
            • 2021-04-14
            • 1970-01-01
            • 2023-03-20
            相关资源
            最近更新 更多