String Stress

BlitzMax Forums/BlitzMax Beginners Area/String Stress

dw817(Posted 2016) [#1]
Being a long-time BASIC programmer, I am familiar with the command MID$ being used for both retrieving a series of characters from a string AND being able to place them in.

I am finding however that BlitzMAX does not allow for this. So I guess it's a pretty simple question for you veterans. What code would I use to make this work ?
a$="apple"

' Mid$(a$,2,1)="z" ' does not work
' a$[1..2]="z" ' does not work
' poke varptr ??

Print a$ ' result should be "azple"



Yasha(Posted 2016) [#2]
Strings are considered values in BlitzMax, even though they're implemented as objects, and are not mutable once they've been constructed. You need to use value-based logic as a result, extracting substrings and combining them to form new result strings:

Local a:String = "apple"
Local from:Int = 1, _to:Int = 2
Local b:String = a[..from] + "z" + a[_to..]


If you really need mutable array-like semantics (perhaps you're doing some very high-performance dense text processing work), you could use an array as an informal string buffer and then use String.FromBytes or String.FromShorts when done. But this is unlikely to be necessary in practice (and immutable semantics are always better style).


dw817(Posted 2016) [#3]
No easier way to do it ? I was hoping maybe I could use Varptr, or PokeByte or something like that.

Your method /from/ and /to/ is very similar to what I'm using now.
a$="apple"

a$=changechar$(a$,2,"z")

Print a$

Function changechar$(a$,b,c$)
  Return Left$(a$,b-1)+c$+Mid$(a$,b+1)
EndFunction
I wanted to use the string as a pointer to graphics so instead of building a 4-byte integer I could build 4-characters instead.

Yet - now I am understanding that strings take 2-bytes per character, whereas I know MANY programming languages where a single string character is 1-byte.
a$="apple"
Print SizeOf(a$) ' 10
a$="apples"
Print SizeOf(a$) ' 12


Thanks for your help, Yasha. If someone knows a way of poking that character right in the string without having to add the beginning and the ending of it, that is what I am really looking for.


Yasha(Posted 2016) [#4]
If you aren't even using it as text, there's really no reason to use a string for this at all. Why not use an array? It'll be clearer and faster:

Local four:Byte[4]
four[0] = $FF
four[1] = 0
four[2] = 0
four[3] = $FF  'four is now blue-with-full-opacity

Int Ptr(Byte Ptr(four))[0] = $FF00FF00  'four is now green-with-full-opacity


If you want to manipulate byte data... use a byte type! Strings are a text type.


dw817(Posted 2016) [#5]
Yeah, you're right. Old habits die hard. Every other language I've used BYTE array just wasn't available so I've always used strings - and now, really to think about it, strings take 2-bytes per character instead of one.

I guess one reason I like strings is I can always use something like mid$(s$,pos,len) and use PRINT to view the contents of that particular area even though I'm using it for binary storage.

Solution:



It may look a little funny, but it'll help me get familiar with byte arrays until I'm using them proper.

Thanks for your help, Yasha !


Yasha(Posted 2016) [#6]
Two minor observations:

1) if you didn't know, arrays also support the same "value-like" tricks as strings. +, :+ etc. Might come in handy. Not really relevant to what you're doing there.

2) bytetostr(map) can be replaced (or implemented) with String.FromBytes(map, map.Length). This will be much more efficient, as it allocates the whole string in one go - as opposed to some ~32500 unnecessary malloc/free cycles. Allocating objects is almost free in BlitzMax - up until a certain size, then it becomes slower as the pool allocator has to fallback to using malloc. You ideally want to avoid very frequent allocation of larger objects, especially in a scenario like the above where they're immediately being copied and discarded after one use. (Again, not important right now - it's a debug print function, nobody cares about performance - but good to know.)

EDIT: oh just noticed the If a[c]=0 ... well, it would still be only two allocations to use String.FromBytes, search for 0 and then slice off the front.


Bobysait(Posted 2016) [#7]

strings take 2-bytes per character instead of one



I might be wrong, but :
A byte (unsigned) is a value between 0 and 255
A string is kind of a pointer to a byte array structur.
-> each character is an ascii value encoded with a single byte.
It doesn't take 2.
A string using more than one byte per character is for non-ascii text and it's just a matter of interpretation of the content of the array.


Yasha(Posted 2016) [#8]
A string using more than one byte per character is for non-ascii text


Right, but there are no ASCII strings in BlitzMax. It uses UCS-2. ASCII isn't good enough for text in the real world. (Neither is UCS-2 for most purposes, but it's adequate for games, which rarely bother with complex typography.)


Brucey(Posted 2016) [#9]
If you want to use a String friendly array, use Short[], since Shorts are 2-bytes.


dw817(Posted 2016) [#10]
Hi Brucey:

Is there a way, like a single command to make a string equal an array of SHORT ? Really I would like that for BYTE, but yeah as it's pointed out, strings take 2-bytes for every character.