0

我的接线员有问题>>

istream& operator>> (istream& is, Matrix& M) {

    char first;

    is>>first;


    for(int i = 0;i<M.rows();i++) {

        for(int j = 0;j<M.cols();j++) {

            is>>M[i][j];
            cout<<M[i][j];

        }

        is>>first;

    }

    return is;
}

我想要 istream 运算符的大小,因为我想更改 for 循环,以便它们不依赖于发送的矩阵,即您发送大小为 1 的矩阵和流,[1 2 3 4; 4 5 6 7; 1 2 3 4]然后发送一个新矩阵应该构造大小(3 * 4)。这样我就可以使用赋值运算符将其分配给矩阵 M。

换句话说,流在形式上"[ 1 2 3; 2 3 4; 4 5 6]"并且;表示新行。我想知道有多少行和列。

4

4 回答 4

2

您可以像这样获取所有行:

vector<string> rows;
string line;

is.ignore(INT_MAX, '['); // ignores all characters until it passes a [

while (std::getline(is, line, ';'))
    rows.push_back(line); // put each row in rows

rows.back().erase(rows.back().find(']')); // erase the ending ]

现在你有每一行字符串rows,然后

for (size_t i = 0; i < rows.size(); ++i) {
    vector<int> items;
    istringstream strstm(rows[i]);

    std::copy(istream_iterator<int>(strstm), istream_iterator<int>(), back_inserter(items));

    // now items is full of the entries, resize the matrix to hold items.size()
    // many items and insert each one into it, or whatever
}
于 2011-12-22T09:01:21.100 回答
1

首先,当然,你需要指定比你更严格的东西。您应该如何处理类似"[ 11 12 13; 21 22; 31 32 33 ]"的内容,例如:0.0为缺失值插入 a 或 set failbit

除此之外,使用std::vector来收集输入将使事情变得更容易一些。类似于以下内容,例如:

template< typename T >
char getRow( std::istream& source, std::vector<T>& dest )
{
    dest.clear();
    char separator;
    source >> separator;
    while ( source && separator != ';' && separator != ']' ) {
        source.unget();
        T tmp;
        source >> tmp;
        if ( source ) {
            dest.push_back( tmp );
            source >> separator;
        }
    }
    if ( source && dest.empty() ) {
        dest.setstate( std::ios_base::failbit );
    }
    return source ? separator : '\0';
}

template< typename T >
char getFirstRow( std::istream& source,
                  std::vector<std::vector<T> >& dest )
{
    dest.clear();
    std::vector<T> row;
    char separator = getRow( source, row );
    if ( source ) {
        if ( row.empty() ) {
            dest.setstate( std::ios_base::failbit );
        } else {
            dest.push_back( row );
        }
    }
    return source ? separator : '\0';
}

template< typename T >
char getFollowingRow( std::istream& source,
                 std::vector<std::vector<T> >& dest )
{
    std::vector<T> row;
    char separator = getRow( source, row );
    if ( source ) {
        if ( row.size() != dest.front().size() ) {
            dest.setstate( std::ios_base::failbit ) ;
        } else {
            dest.push_back( row );
        }
    }
    return source ? separator : '\0';
}

template< typename T >
std::istream&
operator>>( std::istream& source, Matrix<T>& dest )
{
    char separator;
    source >> separator;
    if ( separator != '[' ) {
        source.setstate( std::ios_base::failbit );
    } else {
        std::vector<std::vector<T> > results;
        separator = getFirstRow( source, results );
        while ( separator == ';' ) {
            separator = getFollowingRow( source, results );
        }
        if ( separator != ']' ) {
            source.setstate( std::ios_base::failbit );
        }
        if ( source ) {
            dest.assign( results );
        }
    }
    return source;
}

当然,这意味着该Matrix<T>::assign函数必须能够设置尺寸。并且为了可用,Matrix<T>需要一个默认构造函数,它可能“推迟”实际构造直到 Matrix<T>::assign.

另外:由于 iostream 中错误报告的可能性有限,我们在上述方面受到了一些限制。特别是,我们真的很想区分 input like"[11 12 13; 21"和 nothing(真正的文件结束条件)。但是我们尝试读取分隔符之后"21" 会设置eofbit,我们对此无能为力。(实际上,我们可以创建一个新的状态字,使用std::ios_base::xalloc(), 设置它当且仅当,'['在开始的读取失败并 eofbit设置。但这需要一种非常不标准的方法来检查客户端代码中的错误,这将在反过来会造成层出不穷的维护问题。)

最后,两个元评论:如果这看起来很复杂......它是。输入几乎总是复杂的,因为您必须检查所有各种错误条件。其次,注意使用函数来保持每个单独的操作(有点)简单。初学者经常犯的错误是不要像这样分解事物——几乎总是糟糕的编程,例如,在函数中有一个嵌套循环,除非将数学算法应用于诸如 Matrix. 在这种情况下,解析不是数学算法,你希望将每一行的处理与整体处理分开;在这种情况下,将第一行的处理与其他行分开处理也很有用,因为错误情况不同。(第一行的长度可以大于 0,后面的行必须与前面的行长度相同。)

于 2011-12-22T09:48:06.640 回答
0

问题是流提取操作符需要一个已经构造的对象,它可以修改。您必须调整您的矩阵类,以便它可以动态调整大小。

于 2011-12-22T08:52:42.373 回答
0

无法确定“istream 运算符的大小”,因为它是流,并且当您读取第一个矩阵元素时,没有人可以保证最后一个元素已经存在。您应该首先阅读整个字符串,然后对其进行解析并提取有关输入矩阵大小的信息。之后,您可以通过提供此字符串来使用您的代码stringstream。当然,您必须能够动态更改矩阵的大小。

于 2011-12-22T08:59:07.923 回答