The Middle Class

Archives Forums/BlitzMax Bug Reports/The Middle Class

dw817(Posted 2016) [#1]
Likely many of you have used the command Mid$ or .. as a convenient way of splitting apart text. However, I found recently that there is a difference between these two commands, although for MOST sakes they operate exactly the same.
a$="apple"
b$=Mid$(a$,2,3)
c$=a$[1..4]
Print Len(b$)+" "+b$
Print Len(c$)+" "+c$
Results are:

3 ppl
3 ppl


No problem, now change the first line so you have: a$=""

Now run it.

You get ENTIRELY different results !

0
3


Where could this hurt you ? In a statement like this:
a=Instr(b$,Mid$(c$,d,e))
If c$ is blank then the Instr statement will be TRUE, that is, it will equal one. Why ? Because Instr(a$,b$) will yield 1 if b$ is blank. Yep ! Now try this code:
b$="apple"
c$="elppa"
d=4
e=1
Print Mid$(c$,d,e)
a=Instr(b$,Mid$(c$,d,e))
Print a
Print
Print c$[d-1..d+e-1]
a=Instr(b$,c$[d-1..d+e-1])
Print a
p
2

p
2


Both yield the same result.

Now, change c$="" and run it.

1

0


Different results ! That can hurt you.

Is this an error of BlitzMAX ? Perhaps. What can be done ? Suggest you use only one method so you don't run into problems later.

Be aware when you use .. to grab one or more characters from a string that if your input string itself is blank you do NOT get blank back, but a number of spaces based on the area you selected.

Whereas MID$ most certainly does not ! A blank string will give you blank results. Be careful if you decide to use both of these methods in your code !


TomToad(Posted 2016) [#2]
Not a bug, but the way slicing works. When you type [a..b], you are saying, make a new array of b-a elements and copy elements a through b-1 into that array.
So you have a string "abcdefg" and you do a$ = b$[1..4], a new 3 element array will be created and populated with "bcd". If the resulting array is greater than the array being copied, the rest is filled with a default value, " " in the case of strings, so if you have "ab" and you do b$[1..4], you still get a 3 element array, and "b " will be copied.


dw817(Posted 2016) [#3]
Hi Tom.

Why does the [..] yield a space at all then ? Shouldn't blank input truly be blank output ?

Now I can understand with a command like Rset$() or Lset$() as they deliberately add spaces to the left or right, but not [..] . A slice of nothing should be nothing.


Floyd(Posted 2016) [#4]
As mentioned slices are not just Mid renamed. They are something else.

I find it easiest to imagine the string being sliced as padded with an unlimited number of blanks on both ends. [m..n] means start at position m and and go for length n-m.
Another way to think about it is to imagine m,n as indices which point to locations between characters. And to deal with out of range values gracefully, padding with blanks.

a$ = "012345"[-3..10]

Print
Print ">>>" + a + "<<<"

b$ = Replace( a, " ", "*" )
Print b

In this case we start at position -3 and want length 10-(-3) = 13.

This is done to "         012345          " ( really no limit to the number of blanks. The "0" marks position zero in the original string.

I just rediscovered the fact that the forum will not display consecutive blanks in ordinary text, so I have shown that last line as code.


dw817(Posted 2016) [#5]
I know HTML, Floyd. And you are quite right. If you try this.
<html>
Sally was    a   handful.
</html>
You simply get, Sally was a handful. Now as to the [..], I see what you are doing here.
a$="Orange"
a$=a$[-1..]
yields " Orange" (with a space before the text).

I will simply have to be careful when I use [..] and ensure the value does not go under or over the totals.


Floyd(Posted 2016) [#6]
It's actually quite handy that out of range values are allowed.

For example, if you type LSet into BlitzMax code and press F1 you will see terse help at the bottom of the window. Pressing F1 again goes to additional help which sometimes has more details, but not in this case. Scroll up to the top of the window to seen an overview of the module BRL.Retro which contains LSet. There is also a link to the source. There you will see LSet implemented via slicing.

Rem
bbdoc: Left justify string
returns: A string of length @n, padded with spaces
endrem
Function LSet$( str$,n )
	Return str[..n]
End Function

Rem
bbdoc: Right justify string
returns: A string of length @n, padded with spaces
endrem
Function RSet$( str$,n )
	Return str[Len(str)-n..]
End Function

Notice that indices have default values and can be omitted. Even the expression s$[..] is allowed. It is all of s$.


dw817(Posted 2016) [#7]
Interesting what you wrote here, Floyd.

Yes, this would be quite difficult to do solely with Mid$().

This does answer the age old question of my older routine from GFA:
DEFFN Pad$(A$,A) = A$ + SPACE$(MAX(0,A - LEN(A$)))
Strict
Local a$="Left"

Print fnpad$(a$,5)+"*"

Function fnpad$(a$,b)
  Return a$[..b]
EndFunction
Left *