(unsolved) iostreams. Reading strings separated by spaces and returns AND SLASHES.

Started by
18 comments, last by Zahlman 19 years, 5 months ago
Quote:Original post by the_cyberlord
*** Source Snippet Removed ***
this code gives these errors:
*** Source Snippet Removed ***
And BTW, you can't enter multiple separators like McCloud said, it gives an error. So what do I do???

The multiple separators is for find_first_of, getline only wants one at a time. If you have a set format [so that you know which separator is next at any given time], getline should work. I've never figured out a solution to the problem where the odd separators can occur anywhere except to parse a string rather than a file. Traditionally, I've used strtok, but that function is pure, unadulterated, evil. Don't even consider that option.

I suspect that fixing the newline issue ['/n' rather than '\n'] will fix the problem you're having. The compiler appears confused as to what type '/n' is, but since its not a type at all that's not surprising.

CM
Advertisement
If you wonted to keep the same file format you can try this:

#include <cstddef>#include <cstdlib>#include <algorithm>#include <iterator>#include <string>#include <sstream>#include <vector>#include <fstream>#include <iostream>int main(int argc, char* argv[]) {   typedef std::istreambuf_iterator<char> isbufiter;   typedef std::istream_iterator<std::string> issitr;   typedef std::ostream_iterator<std::string> ossitr;   if(argc == 1) {      std::cerr << argv[0] << " error usage: " << argv[0] << " <file-name>\n";      return EXIT_FAILURE;   }   std::ifstream ifs(argv[1]);   if(!ifs) {      std::cerr << argv[0] << " error could not open file\n";      return EXIT_FAILURE;   }   std::string buf;     std::replace_copy(isbufiter(ifs), isbufiter(), std::back_inserter(buf), '\\', ' ');   std::vector<std::string> vs;   std::istringstream iss(buf);   std::copy(issitr(iss), issitr(), std::back_inserter(vs));   std::copy(vs.begin(), vs.end(), ossitr(std::cout, ", "));   return EXIT_SUCCESS;}


MaulingMonkey's input file:
I like pie.C:\DOSC:\DOS\RUNRUN\DOS\RUN


output:
I, like, pie., C:, DOS, C:, DOS, RUN, RUN, DOS, RUN,
Well, you could use boost. Syntax will depend on exact results desired. Here's the evil version I came up with which should read my example, seperating by:
1) Whitespace
2) \ style slashes
3) using Boost, which alas isn't iostreams, but it's somewhat related (and actually, although I'm not sure, the file iterators may indeed be using iostreams under the hood).

#include <boost/spirit.hpp>#include <boost/spirit/phoenix/binders.hpp>#include <boost/lambda/bind.hpp>#include <boost/format.hpp>#include <string>#include <vector>#include <iostream>using namespace boost;using namespace boost::spirit;using namespace phoenix;using namespace std;struct config_file_grammar : public grammar<config_file_grammar>{	mutable std::vector< std::string > & results;		config_file_grammar( std::vector< std::string > & results )  : results(results) {}		void add_result( const std::string & result ) const { results.push_back( result ); }		template < typename ScannerT > struct definition	{		definition( config_file_grammar const& self )		{			optional_padding //this rule reads 0+ (*) whitespace (space_p).				=	*space_p				;			seperator //this rule reads either optional padding, then(>>) a backslash('\\'), and then(>>) more optional padding, OR (|) 1+ (+) whitespace (space_p).				=	(	optional_padding					>>	'\\'					>>	optional_padding					)				|	+space_p				;			string_entry //this rule reads 1+ (+) characters of any value (anychar_p) that arn't (-) whitespace (space_p) or (|) backslashes('\\')				=	(	+(	anychar_p						-	(	space_p							|	'\\'							)						)					) [ bind( &config_file_grammar::add_result )(self,construct_<std::string>(arg1,arg2)) ] //all of which we then create a string with, which we then call config_file_grammar::add_result with.				;			top				= lexeme_d //this prevents phrase-level parsing, I currently prefer to work allways a character at a time.					[	optional_padding //we read optional padding, followed (>>) by...					>>	(	string_entry //wait for it...						%	seperator //...a LIST of string_entrys seperated with seperators (string_entry % seperator)						)					>>	optional_padding //ending in optional padding...					>>	end_p //we don't really need this here, but this reads 0 characters, but only succeeds if we've reached the end of the input.					]				;		}		rule<ScannerT> top //we now have to declare all those rules we made up			, optional_padding			, seperator			, string_entry			;		rule<ScannerT> const& start() const { return top; } //and the official starting rule must be provided	};};bool read_config_file( const std::string & filename , std::vector< std::string > & results ){	file_iterator<> first( filename.c_str() );	if (!first)	{		std::cerr << format("File: %1% does not exist") % filename << std::endl;		return false;	}	file_iterator<> last = first.make_end();	if (!parse( first , last , config_file_grammar( results ) ).full) return false;		return true;}int main ( int argc , char ** argv ){	std::string filename = "C:\\eclipse\\workspace\\test\\example.txt";	std::vector< std::string > results;	if (!read_config_file( filename , results ))	{		std::cerr << format("Error(s) in file: %1%.") % filename << std::endl;	}	std::cout << "What was read: " << std::endl;	for ( int i = 0 ; i < results.size() ; ++i )	{		std::cout << format("String %1% == %2%") % i % results << std::endl;	}	std::cin.get();	return 0;}


Which results in:
What was read:String 0 == IString 1 == likeString 2 == pie.String 3 == C:String 4 == DOSString 5 == C:String 6 == DOSString 7 == RUNString 8 == RUNString 9 == DOSString 10 == RUN
ehm is it possible to convert strings to ints?
Because this code gives an error:
		while (!f_in.eof())		{		f_in>> input;		//cout << input << endl;		while (input == "v") {			f_in >> value1; f_in >> value2; f_in >> value3;			coords temp(value1,value2,value3);			vertexdata.push_back(temp);			f_in >> input;}		while (input == "vt") {			f_in >> value1; f_in >> value2;			coords2D temp(value1,value2);			texturedata.push_back(temp);			f_in >> input;}		while (input == "vn") {			f_in >> value1; f_in >> value2; f_in >> value3;			coords temp(value1,value2,value3);			normaldata.push_back(temp);			f_in >> input;			cout << input<<endl;}//FROM HERE, THE TOPIC PROBLEM STARTS		while (input == "f") {			f_in >> input;			while (fi < 3) {				GLint temp[3][3];				string tempstring;				cout << input <<endl;				GLint n = input.length();				GLint start, stop;				start = input.find_first_not_of("/");				while (vi < 3) {					stop = input.find_first_of("/", start);					if ((stop < 0) || (stop > n)) stop = n;//this causes the error		//this causes the error					temp[fi][vi] = input.substr(start, (stop - start));					cout << tempstring <<endl;					start = input.find_first_not_of("/", stop+1);}vi++;}fi++;}}

and this is the error:
C:\Documents and Settings\Lord Myth\My Documents\3D\main.cpp(72) : error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >' (or there is no acceptable conversion)
Quote:Original post by the_cyberlord
ehm is it possible to convert strings to ints?


The I/O streams already parse text to other types, if your trying to parse strings in memory to a particular type then use string streams i.e. std::istringstream/std::stringstream.

Post us the file format or example file your trying to read in, i will or someone else will post code.
OK many thanks: here's the file format:
# # Wavefront OBJ file# Converted by the DEEP Exploration 3.5.7.1088# Right Hemisphere, LTD# http://www.righthemisphere.com/# # object Plane01g Plane01v -0.5 -0.5 0v 0.5 -0.5 0v -0.5 0.5 0v 0.5 0.5 0# 4 verticiesvt 0 1vt 0 0vt 1 1vt 1 0# 4 texture verticiesvn 0 0 1# 1 normalsf  3/1/1 1/2/1 4/3/1f  2/4/1 4/3/1 1/2/1# 2 faces// faces are stored like this:  v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3

Since your slash-separated data consists of text representations of numbers, you can read those items directly into an appropriate numeric value. The >> operator for cin is overloaded according to the type of the variable you're reading into, so that this works the way you want it to. Example:

std::string line_type;float values[3];char ignored;// At the beginning of this loop, we're always at the beginning// of a line.while(cin >> line_type) {  // Don't nest while loops here; it just obfuscates things.  // Ideally you should build a look-up table mapping the string  // to an action to take. Look up std::map and functors.  if (line_type == "f") {    // Read in three vertices which are separated by '/' chars    // This is quite fragile and depends on your input being good.    // For more ideas, see    // http://www.augustcouncil.com/~tgibson/tutorial/iotips.html    for (int i = 0; i < 3; i++) {      cin >> values[0] >> ignored >> values[1] >> ignored >> values[2];      make_coord_with(values);    }  }  // Handle other cases similarly  // Do a std::getline and throw it away, to ignore garbage  // at end of line (optional)}
can someone convert this to a filestream? I'm very new to this all and I'm getting a bit confused...
Nobody? Please!
Many, many thanks to the one showing me this with a file stream!
...

...

... Open your file normally, and replace 'cin' with the name of your ifstream object.

This topic is closed to new replies.

Advertisement