2

using visualworks, in small talk, I'm receiving a string like '31323334' from a network connection.

I need a string that reads '1234' so I need a way of extracting two characters at a time, converting them to what they represent in ascii, and then building a string of them...

Is there a way to do so?

EDIT(7/24): for some reason many of you are assuming I will only be working with numbers and could just truncate 3s or read every other char. This is not the case, examples of strings read could include any keys on the US standard keyboard (a-z, A-Z,0-9,punctuation/annotation such as {}*&^%$...)

Medic3000
  • 786
  • 4
  • 20
  • 44
  • Is it always going to represent hex values of decimal digits? If so, just pick out all the even characters. – lurker Jul 23 '15 at 19:17
  • it returns a string of characters. my question is more how can I break apart the string into 2 character chunks, and then determine their int/char value based on ascii standards – Medic3000 Jul 24 '15 at 14:10
  • 1
    We can only speculate what possible strings you might have unless you specify. The narrow scope of the answers so far is due to lack of specification in the problem and narrowly scoped example. The only example you gave is of a string representing hex ASCII values of decimal digits and no further explanation. Now you have, *...examples of strings read could include...*. Is that now comprehensive? It's difficult to answer such a question without being specific. I also asked the question in my comment what whether to assume decimal digits, and you provided no answer (up until now). – lurker Jul 24 '15 at 14:19

3 Answers3

2

Following along the lines of what Max started to suggest:

x := '31323334'.
in := ReadStream on: x.
out := WriteStream on: String new.
[ in atEnd ] whileFalse: [ out nextPut: (in next digitValue * 16 + (in next digitValue)) asCharacter ].
newX := out contents.

newX will have the result '1234'. Or, if you start with:

x := '454647'

You will get a result of 'EFG'.

Note that digitValue might only recognize upper case hex digits, so an asUppercase may be needed on the string before processing.

lurker
  • 56,987
  • 9
  • 69
  • 103
  • dont assume that, any keyboard inputs can be possible, so a string may be varied size or characters from "454647" to "313233343541424344" – Medic3000 Jul 24 '15 at 14:09
  • The issue with Max's sollution is that they didnt read my question. at the beginning I state clearly I'm using VisualWorks. Will this work there? – Medic3000 Jul 24 '15 at 14:14
  • It seems that VisualWorks doesnt allow '<<' for WriteStreams, but for the most part the logic is operating correctly. I'll likely select your answer as the most useful – Medic3000 Jul 24 '15 at 14:24
  • @DarthSheldon the code I provided will actually work for any ASCII character representations, not just digits. Apologies for the `<<` operator, as that is probably a GNU Smalltalk specific construct. I've updated the answer. – lurker Jul 24 '15 at 14:26
  • hi, just a quick heads up: for VisualWorks the correct operator would be 'nextPut:' instead of '<<' but it works perfectly w/ that change. thank you – Medic3000 Jul 24 '15 at 14:29
  • @DarthSheldon yep, that's the more standard selector, which I changed to. :) – lurker Jul 24 '15 at 14:30
0

There is usually a #fold: or #reduce: method that will let you do that. In Pharo there's also a message #allPairsDo: and #groupsOf:atATimeCollect:. Using one of these methods you could do:

| collectionOfBytes |
collectionOfBytes := '9798' 
  groupsOf: 2
  atATimeCollect: [ :group |
    (group first digitValue * 10) + (group second digitValue) ].
collectionOfBytes asByteArray asString "--> 'ab'"

The #digitValue message in Pharo simply returns the value of the digit for numerical characters.

If you're receiving the data on a stream you could replace #groupsOf:atATime: with a loop (result may be any collection that you then convert to a string like above):

...
[ stream atEnd ] whileFalse: [
  result add: (stream next digitValue * 10) + (stream next digitValue) ]
...
Max Leske
  • 5,007
  • 6
  • 42
  • 54
  • I stated clearly that I am using visual works, not Pharo – Medic3000 Jul 24 '15 at 14:13
  • 2
    I'm aware of that. And yes, I did read your question. I tried to show a general way in which this problem can be solved. Others might come along that have the same question but are using VW or Squeak etc. – Max Leske Jul 24 '15 at 15:14
0

in Smalltalk/X, there is a method called "fromHexBytes:" which the ByteArray class understands. I am not sure, but think that something similar exists in other ST dialects.

If present, you can solve this with:

 (ByteArray fromHexString:'68656C6C6F31323334') asString

and the reverse would be:

 'hello1234' asByteArray hexPrintString

Another possible solution is to read the string as a hex number, fetch the digitBytes (which should give you a byte array) and then convert that to a string. I.e.

(Integer readFrom:'68656C6C6F31323334' radix:16)
    digitBytes asString

One problem with that is that I am not sure about which byte-order you will get the digitBytes (LSB or MSB), and if that is defined to be the same across architectures or converted at image loading time to use the native order. So it may be required to reverse the string at the end (to be portable, it may even be required to reverse it conditionally, depending on the endianess of the system.

I cannot test this on VisualWorks, but I assume it should work fine there, too.

blabla999
  • 3,130
  • 22
  • 24