Kwaku
Kwaku

Reputation: 276

How to construct a String instance from a sequence of integers?

I would like to create a test string from Unicode code points

Something like this

 65 asCharacter asString,
 66 asCharacter asString,
 67 asCharacter asString,
 65 asCharacter asString,
769 asCharacter asString

Or

String with: 65 asCharacter
       with: 66 asCharacter
       with: 67 asCharacter
       with: 65 asCharacter
       with: 769 asCharacter

This works but

I am looking for a way to convert an array of integer values to an instance of class String.

#(65 66 67 65 769)

Is there a built in method for this? I am looking for an answer like this What is the correct way to test Unicode support in a Smalltalk implementation? one, but for Strings.

Upvotes: 4

Views: 254

Answers (4)

aka.nice
aka.nice

Reputation: 9382

Please, consider the following as awfully hackish, undocumented, unsupported and thus absolutely wrong way to do it!
You would think that you cannot mix characters and integers that easily, err you can:

'' asWideString copyReplaceFrom: 1 to: 0 with: (#(65 66 67 65 769) as: WordArray).

Indeed, this goes thru a primitive that doesn't really check for the class, but just for the fact that both receiver and argument are VariableWord classes...

For the very same reason (depending on WriteStream implementation - let's say fragile) this can work:

^'' asWideString writeStream
    nextPutAll: (#(65 66 67 65 769) as: WordArray);
    contents

The same apply to ByteString and ByteArray.

And of course, in the same vein, let's not forget the most convoluted way to do it, BitBlt:

^((BitBlt toForm: (Form new hackBits: (WideString new: 5)))
    sourceForm: (Form new hackBits: (#(65 66 67 65 769) as: WordArray));
    combinationRule: Form over;
    copyBits;
    destForm) bits

We again exploit the WordArray nature of WideString to serve as the container for the bits of a Form (a bitmap).

Hopefully this answer won't get too many votes, it doesn't deserve it!

Upvotes: 1

Leandro Caniglia
Leandro Caniglia

Reputation: 14858

Here is a "low level" variant:

codepoints := #(65 66 67 65 769).

string := WideString new: codepoints size.
codepoints withIndexDo: [:cp :i | string wordAt: i put: cp].
^string

Upvotes: 1

Peter Uhnak
Peter Uhnak

Reputation: 10217

Many ways

1. #streamContents:

Use stream if you are doing larger string concatenation/building as it is faster. If just concatenating couple of strings use whatever is more readable.

String streamContents: [ :aStream |
    #(65 66 67 65 769) do: [ :each |
        aStream nextPut: each asCharacter
    ]
]

or

String streamContents: [ :aStream |
    aStream nextPutAll: (#(65 66 67 65 769) collect: #asCharacter)
]

2. #withAll:

String withAll: (#(65 66 67 65 769) collect: #asCharacter)

3. #collect:as: String

#(65 66 67 65 769) collect: #asCharacter as: String

4. #joinUsing: the characters

(#(65 66 67 65 769) collect: #asCharacter) joinUsing: ''

Note:

At least in Pharo you can use either [ :each | each selector ], or just simply #selector. I find the latter more readable for simple things, but that may be personal preference.

Upvotes: 8

Kwaku
Kwaku

Reputation: 276

Construct the String instance with #withAll:

String withAll: 
   (#(65 66 67 65 769) collect: [:codepoint | codepoint asCharacter])

Upvotes: 4

Related Questions