'CharArray: Option Public Option Explicit %REM The CharArray class converts a string to a (virtual) character array. This can be useful if you need to step through a string character by character, because it's a LOT faster to feed the string into a CharArray and read it using getCharAt() than it is to use Mid() to go one character at a time. Here's how you use it: Dim ca As New CharArray() Call ca.appendString( someBigString ) For i = 1 To ca.getLength() Print ca.getCharAt(i) Next NOTE that the getCharAt() method is one-based, so that the first character will be at getCharAt(1). This is consistent with other LotusScript String handling functions like Instr, Left, Mid, etc. The way this works is, we have an internal buffer of 30,000 characters (well, actually 30,001 since it's zero-based), and if we add more characters than that, we just create a new CharArray internal to this class. If the internal CharArray needs more characters than it can hold, it creates it's own internal CharArray, and so forth. When we're reading characters back out, we just call the internal CharArray(s) recursively to get the position we need. version 1.0 Julian Robichaux -- http://www.nsftools.com October 15, 2007 %END REM Class CharArray Private buffer(0 To 30000) As String*1 Private bufpos As Integer Private maxpos As Integer Private child As CharArray Private hasChild As Integer Public Sub New () maxpos = Ubound(buffer) End Sub '** Use appendString to add the String that you want to turn into '** a character array. You can also feed multiple Strings in to '** build a longer String by calling appendString over and over. Public Sub appendString (txt As String) '** if we already filled our internal buffer, feed the extra text '** into our internal CharArray If (bufpos > maxpos) Then If Not hasChild Then Set child = New CharArray() hasChild = True End If Call child.appendString(txt) Exit Sub End If Dim txtLength As Long txtLength = Len(txt) '** I did a handful of tests, and 50 was the best number for me If (txtLength > 50) Then '** Strings longer than 50 chars get split in half (it's faster to '** step through smaller strings) Dim half As Long half = Fix(txtLength / 2) Me.appendString(Left(txt, half)) ' Me.appendString(Mid(txt, half+1)) ' Right() is just a hair faster here Me.appendString(Right(txt, txtLength - half)) Else '** the String is small enough, so step through it and add each '** character to our internal array (feeding to the internal CharArray '** if we need to) Dim i As Integer For i = 1 To txtLength If (bufpos > maxpos) Then Call Me.appendString(Mid(txt, i)) Exit Sub End If buffer(bufpos) = Mid(txt, i, 1) bufpos = bufpos + 1 Next End If End Sub '** Return the total number of the characters in this CharArray (along with '** any child CharArrays we've also populated). This would be the size '** of the array. Public Function getLength () As Long If Not hasChild Then getLength = bufpos Else getLength = bufpos + child.getLength End If End Function '** Return the character at the specified position. NOTE that even though '** the internal array is zero-based, this function considers one to be the '** first position in the array. This makes it consistent with native LotusScript '** String functions like Instr, Left, Mid, etc. Public Function getCharAt (i As Long) As String '** it's a little faster to ignore errors here than to do '** a lot of explicit bounds checking, because in almost '** all cases we should be getting a valid request On Error Resume Next If (i <= bufpos) Then getCharAt = buffer(i-1) Else getCharAt = child.getCharAt(i - bufpos) End If End Function '** Return the internal character array (and all child arrays) as a String. Public Function toString () As String Dim fullString As String fullString = Left( Join(buffer, ""), bufpos ) If hasChild Then fullString = fullString + child.toString() End If toString = fullString End Function End Class Sub Initialize '** here's a test you can run ' Call TestCharArray(5000) End Sub Sub TestCharArray(iterations As Long) Dim txt As String Dim i As Long Dim bigString As String Dim startTime As Single Dim ca As New CharArray() Print "===================================================" txt = "This is a sentence. " ' ASCII ' txt = "Iñtërnâtiônàlizætiøn " ' accented characters ' txt = "  " ' high end of Unicode iterations = 5000 Print "Base string length = " & Len(txt) & "; Total size should be " & (Len(txt) * iterations) '** First, we'll build the CharArray up with multiple calls to appendString, '** to see how long it takes to build a long string that way. startTime = Timer Set ca = New CharArray() For i = 1 To iterations Call ca.appendString(txt) Next Print "BUILDING THE CHARARRAY IN A LOOP" Print "ca length = " & ca.getLength() Print "last char = '" & ca.getCharAt(ca.getLength()) & "'" Print "Elapsed time = " & (Timer - startTime) '** Next, we'll take that big String we just created and dump it into the '** CharArray in one big chunk bigString = ca.toString() startTime = Timer Set ca = New CharArray() Call ca.appendString(bigString) Print "BUILDING THE CHARARRAY ALL AT ONCE" Print "ca length = " & ca.getLength() Print "last char = '" & ca.getCharAt(ca.getLength()) & "'" Print "Elapsed time = " & (Timer - startTime) '** Sanity check -- look at the first bit of characters, as well as some of '** the characters at our boundary between the base CharArray and its '** internal CharArray Dim printString As String For i = 1 To 55 printString = printString + ca.getCharAt(i) Next Print printString printString = "" For i = 29995 To 30005 printString = printString + ca.getCharAt(i) Next Print printString '** Now see how long it takes to read the characters out of the array. startTime = Timer Dim j As Long Dim char As String*1 For i = 1 To ca.getLength() char = ca.getCharAt(i) j = j + 1 Next Print "READING CHARACTERS" Print "count = " & j & "; Elapsed time = " & (Timer - startTime) End Sub