Sunday, February 1, 2009

Characters, Strings, and Things

Sebastian Nozzi asked on the beginners list:
I've been struggling a bit with some basics about Strings for which I
couldn't find an answer (yet).

1) How to construct a String from Characters?

For example, I want to construct a String from the Chatacter literals:

$H $I
Character cr
$T $H $E $R $E

2) How to replace a sequence of Characters in a String for others?

For exaple, I want to replace every 'HI' (in this case only one) for
'HELLO' in the String above (not necesarily destructively, getting a
new String is also ok). Is there a quick way to do that?

Thanks in advance!
Smalltalk isn't known for being a scripting language. The runtime and object model are very similar to Ruby, but it is lacking all of the little Perl-isms that we associate with scripting languages.

To deal with the input characters, it is useful to have them in an array. A traditional Smalltalk array with characters would look like this #($a $b $c) but it isn't obvious what to do with the carriage return. For this, the Squeak brace array is handy and also works in Pharo.

characters := {$H.$I.Character cr. $T.$H.$E.$R.$E}.

It isn't terribly portable to other Smalltalks, but it sure is easy to type. Now we've got an array of characters, how to create the new String? Another Squeak-ism is the class method #streamContents:.
It takes a one argument block. The argument is a writeable stream that will return its contents at the end. I have to admit I was thrown by it the first time I saw it.

string := String streamContents: [:writeStream | characters do: [:c | writeStream nextPut: c]].
Like the brace array, it isn't very portable to other Smalltalks, but it is pretty handy.

That leaves us with replacing. I opened the method finder and typed replace into the search box.



That gives us the following complete solution:

| characters string |
characters := {
$H.$I.Character cr. $T.$H.$E.$R.$E}.
string := String streamContents: [:writeStream | characters do: [:c | writeStream nextPut: c]].
string copyReplaceAll: 'HI' with: 'HELLO'

Enjoy!

No comments: