I am trying to read from a stream of strings and numbers delimited by commas similar to the way I have read from a stream of strings and numbers delimited by spaces.
Example delimited by spaces (which works):
stream = StringToStream["Apple Jack 1 123.456\nOrange Jill 2 456.789\n"];
While[! EndOfFile === (data =
Read[stream, { Word, Word, Number, Number }]),
Print["Fruit:", data[[1]], " Name:", data[[2]],
" Integer:", data[[3]], " Real:", data[[4]]];
]
Results:
Fruit:Apple Name:Jack Integer:1 Real:123.456
Fruit:Orange Name:Jill Integer:2 Real:456.789
Example delimited by commas (which does not work):
stream = StringToStream["Apple,Jack,1,123.456\nOrange,Jill,2,456.789\n"];
While[! EndOfFile === (data =
Read[stream, { Word, Word, Number, Number }]),
Print["Fruit:", data[[1]], " Name:", data[[2]],
" Integer:", data[[3]], " Real:", data[[4]]];
]
Results:
Fruit:Apple,Jack,1,123.456 Name:Orange,Jill,2,456.789 Integer:EndOfFile Real:EndOfFile
It appears that commas are not default separators.
I added WordSeparators -> ","
as an option to Read
. Note NumberSeparator
is not valid option for Read
.
stream = StringToStream["Apple,Jack,1,123.456\nOrange,Jill,2,456.789\n"];
While[! EndOfFile === (data =
Read[stream, { Word, Word, Number, Number }, {WordSeparators -> ","}]),
Print["Fruit:", data[[1]], " Name:", data[[2]],
" Integer:", data[[3]], " Real:", data[[4]]];
]
Results:
Read::readn: Invalid real number found when reading from StringToStream[Apple,Jack,1,123.456
Orange,Jill,2,456.789
]. >>
Fruit:Apple Name:Jack Integer:$Failed Real:EndOfFile
Read::readn: Invalid real number found when reading from StringToStream[Apple,Jack,1,123.456
Orange,Jill,2,456.789
]. >>
Fruit:1 Name:123.456 Integer:$Failed Real:EndOfFile
...
Well this works for words, but not for numbers.
I can always do this, but this seems a little overkill:
stream = StringToStream["Apple,Jack,1,123.456\nOrange,Jill,2,456.789\n"];
While[! EndOfFile === (record = Read[stream, Record]),
data = MapAt[ToExpression, StringSplit[record, ","], {{3}, {4}}];
Print["Fruit:", data[[1]], " Name:", data[[2]],
" Integer:", data[[3]], " Real:", data[[4]]];
]
Results:
Fruit:Apple Name:Jack Integer:1 Real:123.456
Fruit:Orange Name:Jill Integer:2 Real:456.789
Is there something thing that I am missing with Read
?
Post answer analysis ...
The check was awarded to the answer that best answered the above question as I am not one to change the rules of the game while it is being played. However the question was flawed by an assumption that I made that both the parsing and conversion in Read
would be the most efficient.
If one is looking for the most efficient solution, the following are some results from answers presented (timings are in seconds for 10000 iterations):
Implementation | Timing
-------------------------------+---------
question - Read[] with spaces | 0.220325
Matariki - wo/Sequence[] | 0.250499
Matariki - w/Sequence[] | 0.345603
Heike - Word, Word, Word, Word | 0.351137
Heike - Riffle | 0.380684
question - overkill | 0.395058
ToExpression
to turn them into numbers. $\endgroup$Word, Word, Number, Number
to useWord, Word, Number, Real
? $\endgroup$Word
shows that the comma is not removed until the next token is pulled from the stream, and whileWord
will respect theWordSeparators
,Number
does not. It insists on whitespace only. It seems clear thatWordSeparators
is intended as a list of field separators, but it doesn't act that way. $\endgroup$