String left,mid and right

Monkey Forums/Monkey Programming/String left,mid and right

Virtech(Posted 2011) [#1]
Is there some way to perform operations like left/mid/right on strings in monkey? Im surprised those functions are not included in the language :(


muddy_shoes(Posted 2011) [#2]
I've only ever seen those functions in Excel/VB, so they're not exactly common library issue as far as I'm aware. Monkey strings are slice-able though, so what are you wanting to do that you find you can't?


Warpy(Posted 2011) [#3]
To elaborate slightly on what muddy_shoes said:

Left(i):
str[..i]

Right(i):
str[i..]

Mid(i,j):
str[i..j]



Virtech(Posted 2011) [#4]
@muddy_shoes
At the moment I need left() for debugging purposes. I want to print floats values using text command. But I dont want to output 20 or so decimals, and would like to truncate the numeric string to the first 5 or 6 decimal place. Also I've been using left,mid and right on lots of occasions before in other languages, so I know Im going to need those functions again for manipulating strings. So the question really is, what alternatives are there in monkey to accomplish the same result as left..etc

@warpy
Could you please elaborate on your example?
How can I use str[..i] to truncate the lenght of characters when printing var value?
local value#=Rnd(1.0) 
Text "value: "+value,x,y



Virtech(Posted 2011) [#5]
Ok, figured it out :)

Example left...
local value#=Rnd(1.0) 
Text "value: "+String(value)[..5],x,y



ziggy(Posted 2011) [#6]
This may help:
Function Left:String(value:String, index:int)
	If index<0 then Error "Illegal call. Index must be greater than zero."
	Return value[..index]
End

Function Right:String(value:String, index:int)
	If index < 0 Then Error "Illegal call. Index must be greater than zero."
	Return value[ - index ..]
End

Function Mid:String(value:String, index:Int, count:Int)
	If index < 0 Then Error "Illegal call. Index must be greater than zero."
	If count < 0 Then Error "Illegal function call. count must be greater than zero."
	index-=1
	Return value[index..(index+count)]
End

Function Mid:String(value:String, index:Int)
	If index < 0 Then Error "Illegal call. Index must be greater than zero."
	index -=1
	Return value[index..(value.Length-index)]
End

Function Instr(value:String, sub:String, start = 1)
	If start < 0 Then Error "Illegal call. start must be greater than zero."
	Return value.Find(sub, start - 1) + 1
End Function

Function Replace:String( value:String,sub:String,replaceWith:String )
	Return value.Replace( sub,replaceWith )
End Function

Function Lower:String( str$ )
	Return str.ToLower()
End Function

Function Upper:String( str$ ) 
	Return str.ToUpper()
End Function



Warpy(Posted 2011) [#7]
Something like this:
Local value#=Rnd(0,1)
Print "value: "+String(value)[..5]


Note that you have to explicitly cast the number to a string before you can slice it.


Warpy(Posted 2011) [#8]
Crumbs, someone phones me and when I come back two more posts have appeared!


Virtech(Posted 2011) [#9]
Useful functions ziggy, thanks!


Cartman(Posted 2011) [#10]
Thanks ziggy. I'm happy people are taking the time to write these helpful functions. Makes it easier to convert code.


degac(Posted 2011) [#11]
http://www.monkeycoder.co.nz/Community/posts.php?topic=269#1729

I made a 'copy & paste' of the BlitzMax functions+some ones personalized.


Warpy(Posted 2011) [#12]
How is it that in all my many posts in this thread I forgot to mention the most important fact: 99% of the time, when you think you can do something with string slices, that is a really bad idea.

Truncating numbers is not something you should be doing just by manipulating the string representation of a float. Do this instead:

Function round$(value#,places)
	places = Max(places,0)	'sanity check - you can't round to a negative number of decimal places
	
	If value<0 Return "-"+round(-value,places)
	
	Local i = Floor(value)	'get integer part
	value -= i				'take away integer part to be left with fractional part
	value *= Pow(10,places)	
	Local f = Floor(value)	'round off unwanted digits
	If value-f>=.5 f+=1		'round up if first digit rounded off is 5 or greater
	If f = 0
		Return String(i)
	Else
		Return i+"."+f
	Endif
End

Function Main()
	Local value#=Rnd(100,200)
	Print "Round "+value+" to "
	For Local c=0 To 3
		Print c+" decimal places: "+round(value,c)
	Next
	Print "Round 1.35 to 1 decimal place (round up): "+round(1.35,1)
	Print "negative pi to 3 decimal places: "+round(-PI,3)
End



Virtech(Posted 2011) [#13]
Thanks for the added insight warpy. But there are plenty of other cases where you need to manipulate strings for one reason or another. So why is it such a bad idea to operate on string slices?


Warpy(Posted 2011) [#14]
Generally because the problem you're trying to solve isn't usually just a problem about strings, so the routine you come up with will probably be quite error-prone.


hardcoal(Posted 2014) [#15]
This doesnt work well..

Function Right:String(value:String, index:int)
Return value[-index..]
End

I did this for the moment

Function Right:String(Strng:String, Length:Int)
Local I, Start, Answer:String
Length = Length - 1
Start = Len(Strng) - Length
For I = Start To Len(Strng)
Answer = Answer + Mid(Strng, I, 1)
Next
Return Answer
End Function

Ziggy's Function for some reason keep returning the orginal Value as it was


therevills(Posted 2014) [#16]
Ziggy's works fine for me:

Strict

Function Main:Int()
	Local str:String = "Hello"
	Local newStr:String = Right(str, 2)
	Print(newStr)
	Return 0
End

Function Right:String(value:String, index:int)
	Return value[-index..]
End

Prints out "lo" as expected...


Raph(Posted 2014) [#17]
Also, Hardcoal,. every time you slice a string you get a new string generated; by putting Mid in a loop, you're generating a lot of garbage.


hardcoal(Posted 2014) [#18]
@Raph I thought that when you are out of the Function the Garbage Cleaner Automatically Cleans it...
omg thats bad

In Ziggys Command I Did This Right(UserLine, Len(UserLine) - Len(UserLineWord))
This should reduce the a word from the user line but instead it returned the same result..

is it also correct for blitzmax this garbage issue?


therevills(Posted 2014) [#19]
Monkey's GC (or the Targets GC) will clear it up, but it is best not to create junk in the first place.

I gather your Len function returns the length of a string... Why dont you use Monkey's functions such as Length etc?

Anyway again this works:
Strict

Function Main:Int()
	Local UserLine:String = "Hello"
	Local UserLineWord:String = "lo"
	Local newStr:String = Right(UserLine, Len(UserLine) - Len(UserLineWord))
	Print(newStr)
	Return 0
End

Function Len:Int(value:String)
	Return value.Length
End

Function Right:String(value:String, index:Int)
	Return value[-index..]
End


Maybe post a runnable example so we know exactly what is your problem.


hardcoal(Posted 2014) [#20]
ok i will. its not urgent atm :)


ziggy(Posted 2014) [#21]
I've modified the above function to include parameters validation ala traditional basic. Maybe that was causing you runtime problems, Hardcoal.