Re: Suggestions to reading txt files?
On 4 Mar, 22:25, none <""mort\"@(none)"> wrote:
I have a .txt file containing strings ordered as a row*column
matrix, eg.:
a basd asdasd asdasd ada asdasd asdda
b basd asdasd asdasd ada asdasd asdda
c basd asdasd asdasd ada asdasd asdda
c basd asdasd asdasd ada asdasd asdda
The number of columns for each row is constant. I am trying to
write a function that given a txt file as the one above
returns the i,j element like:
std::string file = "c:\test.txt";
int rows = numberOfRows(file);
int columns = numberOfColumns(file);
for (int i=0; i<rows; i++) {
for (int j=0; j<columns; j++) {
std::string elem = readCell(i,j,file);
}
}
Any hints on a smart version of readCell are welcome since my
current version is pretty ugly...maybe there are some build in
functionality for this kind of txt file parsing that I have
missed ?
You'll have to define the problem a little bit better before we
can answer the question: are the number of rows and columns
known before hand, or does the program have to deduce them from
the code? What determines a column: white space, fixed length,
or? (I assume that '\n' determines a row. Otherwise, calling
them .txt files is perhaps not a good idea.) Are you looking
for true random access: read a particular element without having
to read all of the preceding?
If the file will fit into memory, and the columns are white
space separated, perhaps something like the following would do
the trick:
class FormattedFile
{
std::vector<std::vector<std::string> > myData;
static Fallible<std::vector<std::string> > readLine(
std::istream& source );
public:
explicit FormattedFile( std::istream const& source );
int rows() const { return myData.size(); }
int columns() const { return myData[0].size(); }
std::string at( int row, int column ) const
{
assert( row >= 0 && row < myData.size()
&& column >= 0 && column < myData[0].size() );
return myData[row][column];
}
};
FormattedFile::FormattedFile(
std::istream& source)
{
Fallible<std::vector<std::string> >
line( readLine( source ) );
if ( ! line.isValid() ) {
throw SomeError( "File is empty" );
}
int columns = line.value().size();
myData.push_back( line.value() );
line = readLine( source );
while ( line.isValid() ) {
if ( line.value().size() != columns ) {
throw SomeError( "Format error" );
}
myData.push_back( line.value() );
line = readLine( source );
}
}
Fallible<std::vector<std::string> >
FormattedFile::readLine( std::istream& source )
{
Fallible<std::vector<std::string> > result;
std::string line;
if ( std::getline( source, line ) ) {
std::istringstream tmp( line );
std::vector<std::string> entry;
std::string element;
while ( tmp >> element ) {
entry.push_back( element );
}
result.validate( entry );
}
return result;
}
This is only really valid for smaller files, however; once the
data starts occupying a significant part of the memory, it
ceases to be appropriate.
--
James Kanze