This post originated from an RSS feed registered with Agile Buzz
by James Robertson.
Original Post: Another extension to PeekableStream
Feed Title: Richard Demers Blog
Feed URL: http://www.cincomsmalltalk.com/rssBlog/rademers-rss.xml
Feed Description: Richard Demers on Smalltalk
In A Peek at some more Extensions Travis Griggs points out that "There are two basic things we do with streams, skip their contents, and extract them." And then he provides the Smalltalk code for two nifty methods he had written as extensions to class PeekableStream.
Well, there's one more basic thing we do with streams, we peek to see what's coming next. And that's what I needed to do when I had to detect any HTML entities (sequences of the form &xxx; that represent < > & ") in a string and replace them with their single character encodings. One possibility was to tokenize the string, translate the tokens as needed, and then reassemble the string -- but that seemed like too much work. The other possibility was to read, parse and translate the string in a single pass on a ReadStream.
A ReadStream on any collection moves a cursor forward and back one object at a time, and on a String that means one character at a time. It also means that you can peek ahead at only one character at a time, which is not very convenient when looking for multi-character entities.
I'd be surprised to learn I was the first to have this problem, but I couldn't find any existing method that would let me "peek ahead for a specific sequence of objects." So I wrote the following as an extension to PeekableStream:
peekForAll: aCollection
"Answer false and do not move the position if the next sequence of objects
does not equal the corresponding objects in aCollection, or if the receiver is at the end.
Otherwise, answer true and increment position for the number of objects in aCollection."
| peek |
aCollection isEmpty ifTrue: [^false].
1 to: aCollection size
do:
[:index |
self atEnd
ifTrue:
[self skip: (index - 1) negated.
^false].
peek := self next.
(aCollection at: index) = peek
ifFalse:
[self skip: index negated.
^false]].
^true