4

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.

Community
  • 1
  • 1
Kwaku
  • 276
  • 2
  • 15
  • I think that even if there were a standard way of doing so, it is so simple to write a loop generating string or StringBuilder which allows you to customize the format of the final string, that it is probably better just to go ahead and write your own. Good luck. – Owen Ivory Dec 11 '15 at 21:40
  • 1
    There is no **StringBuilder** in Squeak/Pharo. This is just what I am looking for. – Kwaku Dec 11 '15 at 21:42

4 Answers4

8

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.

Peter Uhnak
  • 9,617
  • 5
  • 38
  • 51
4

Construct the String instance with #withAll:

String withAll: 
   (#(65 66 67 65 769) collect: [:codepoint | codepoint asCharacter])
Kwaku
  • 276
  • 2
  • 15
1

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
Leandro Caniglia
  • 14,495
  • 4
  • 29
  • 51
1

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!

aka.nice
  • 9,100
  • 1
  • 28
  • 40