Code archives/Miscellaneous/Format String

This code has been declared by its author to be Public Domain code.

Download source code

Format String by N2009
This is a fairly simple FormatString function - it takes in a format string and an array of objects and returns a string with string representations of those object for every insertion found. It's not really proper formatting, unfortunately, but at least it works for my purposes.

Insertions in the format string are marked by \<index>. All indices are one-based unsigned integers. Indices smaller than 1 and larger than the number of objects passed will fail an assertion, and that will probably bring your application to a screeching halt. You can escape an insertion point using another \.

For example:
' Standard insertion points
Print FormatString("\1 \2 \003 ", [Object("Foo"), Object(Null), Object("Wimbleton")])								' => Foo Null Wimbleton

' Escaped insertion points
Print FormatString("\\1 \\2 \\003", [Object("Foo"), Object(Null), Object("Wimbleton")])								' => \1 \2 \003

' Slightly practical example
Print FormatString("TTypeID.ForName(~q\1~q).FindMethod(~q\2~q).Invoke(\3, args)", ["TList", "AddLast", "obj"])		' => TTypeId.ForName("TList").FindMethod("AddLast").Invoke(obj, args)
SuperStrict

Function FormatStringWithList$(format$, list:TList)
	Local arr:Object[]
	If list Then
		arr = list.ToArray()
	EndIf
	Return FormatString(format, arr)
End Function

Function FormatString$(format$, objects:Object[])
	Const CHAR_0% = 48
	Const CHAR_9% = 57
	Const CHAR_SLASH% = 92
	
	Local strings:String[objects.Length]
	
	For Local index:Int = 0 Until objects.Length
		If objects[index] Then
			strings[index] = objects[index].ToString()
		Else
			strings[index] = "Null"
		EndIf
	Next
	
	Local numberIndices:Int[] = [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]
	Local numberLengths:Int[16]
	Local numbers:Int[16]
	Local numberIndex:Int = 0
	Local escape:Int = False
	Local length:Int = 0
	Local char:Int
	
	For Local index:Int = 0 Until format.Length
		char = format[index]
		
		If escape Then
			If CHAR_0 <= char And char <= CHAR_9 Then
				If numberLengths[numberIndex] = 0 Then
					numberIndices[numberIndex] = index-1
				EndIf
				
				char :- CHAR_0
				numbers[numberIndex] :* 10
				numbers[numberIndex] :+ char
				numberLengths[numberIndex] :+ 1
				Continue
			ElseIf numberIndices[numberIndex] <> -1 Then
				numbers[numberIndex] :- 1
				Assert numbers[numberIndex] >= 0 And numbers[numberIndex] < strings.Length ..
				 	Else "FormatString: Index out of range: index must be >= 1 and <= objects.Length"
				length :+ strings[numbers[numberIndex]].Length
				numberIndex :+ 1
				escape = False
			EndIf
		EndIf
		
		If char = CHAR_SLASH Then
			If Not escape Then
				If numberIndex >= numbers.Length Then
					numbers = numbers[..numbers.Length*2]
					numberLengths = numberLengths[..numbers.Length]
					numberIndices = numberIndices[..numbers.Length]
				EndIf
				escape = True
				Continue
			Else
				escape = False
			EndIf
		EndIf
		
		length :+ 1
	Next
	
	If escape And numberIndices[numberIndex] <> -1 Then
		numbers[numberIndex] :- 1
		length :+ strings[numbers[numberIndex]].Length
	EndIf
	
	Local buffer:Short Ptr = Short Ptr MemAlloc(length * 2)
	Local p:Short Ptr = buffer
	
	numberIndex = 0
	escape = False
	For Local index:Int = 0 Until format.Length
		If index = numberIndices[numberIndex] Then
			index :+ numberLengths[numberIndex]
			Local innerString$ = strings[numbers[numberIndex]]
			For Local innerStringIndex:Int = 0 Until innerString.Length
				p[0] = innerString[innerStringIndex]
				p :+ 1
			Next
			numberIndex :+ 1
			Continue
		ElseIf Not escape And format[index] = CHAR_SLASH Then
			escape = True
			Continue
		EndIf
		escape = False
		
		p[0] = format[index]
		p :+ 1
	Next
	
	Local output$ = String.FromShorts(buffer, length)
	MemFree(buffer)
	Return output
End Function

Comments

None.

Code Archives Forum