Library tutorials & articles

String Concatenation Component

The solution

There are times when a solution based on passing strings - instead of passing function pointers or function objects capable of outputting strings - is favorable. For example, let's say I have a general routine that asks the user to verify their billing information before they make a purchase, and this routine needs to output a summary of what the user is buying. You might be tempted to say:

<%
  ' Output your purchase summary...
  ' ...then output your billing information verification system.
%>

but what if your billing information verification code needs to sprinkle HTML on boths sides of the purchase summary. Then you're better off passing that purchase summary - as a string - to the billing information verification code. You could put together some sort of "object that outputs purchase summaries when this method is called" type of system - and VBScript allows for this type of system - but let's keep things simple and pretend we just want to pass in a string and we need efficient string concatenation.

Enter StrCat.Catter. "Catter" is a C++ COM component with a very small interface. Here's typical usage of it:

<%
  Dim strcat
  Set strcat = Server.CreateObject("StrCat.Catter")

  Dim rs
  Set rs = ExecuteSql("SELECT Username FROM Users")

  do until rs.EOF
    strcat rs(0) & "<br>" & vbCrLf
    rs.MoveNext
  loop

  Dim some_str
  some_str = strcat.Dump
  Set strcat = nothing

  Response.Write some_str
%>

That's pretty simple, isn't it? By having the concatenation method be the default method, you just say the Catter's name - in this case strcat - and it just tacks on the string you give it. When you're ready to use the whole string, call Dump and you've got it!

Next, we'll look at the implementation of our Catter class and performance tests.

Interface
For those who know IDL - or can fake it - Catter's interface is as follows:

[id(0), helpstring("Add a string to the end of this. Like str = str & .")]
HRESULT Cat([in] BSTR strToAdd);

[id(1), helpstring("Compute the total string for this.")]
HRESULT Resolve([out, retval] BSTR* pStrOutput);

[id(2), helpstring("Empty the contents of this.")]
HRESULT Reset();

[propget, id(3), helpstring("Get the current length of the total string. Like Len, but much faster.")]
HRESULT Length([out, retval] int *pVal);

[id(4), helpstring("Add a string to the front of this. Like str = & str.")]
HRESULT Prepend([in] BSTR strToPrepend);

[id(5), helpstring("Surround the current contents with a before and after string. Like str = & str & .")]
HRESULT Surround([in] BSTR strToPrepend, [in] BSTR strToAppend);

[id(6), helpstring("Dump = Resolve then Reset. Returns the total strings, and empties the contents of this.")]
HRESULT Dump([out, retval] BSTR* pStrOutput);

[id(7), helpstring("Synonym for Cat. Like str = str & .")]
HRESULT Append([in] BSTR strToAdd);

As you can see, this is general-purpose string assembly engine. At first there was just Cat and Resolve. Then I found that I needed Length, Prepend, and Surround. I mostly use Dump instead of Resolve because it frees resources sooner. Append and Reset are included for completeness.

Comments

  1. 06 Jun 2003 at 00:17

    A great idea!  You can also reduce concatenation times by using arrays and the built-in Join() function.  No components required.  Similar performance gain.  Very readable syntax (once you understand the Join arguments).  


    StringVar = JOIN( StringArray(), ElementSeparatorText )


    Redim S(4)
    S(0) = "This is text line 1"
    S(1) = "This is text line 2"
    S(2) = "This is text line 3"
    S(3) = "This is text line 4"
    S(4) = "This is text line 5"


     'assign lines to string variable with comma separator


    vMyString = join(S, ",")


     'dump lines to screen, one element per visual line ("&" executes once)


    response.write join(S, "<br>" & VbCrLf)


     'output array as a table row (elements are separated with "</td><td>")


    response.write "<tr><td>" & join(S, "</td><td>" ) & "</td></tr>"


     'build an option list of codes that exist in a database


    set rs = CreateObject("ADOR.Recordset")
    rs.Open "select [TypeCode] from [CodeTable] order by [TypeCode]", myConnectString, adOpenStatic
    S = rs.getrows '<-- very fast!
    rs.close
    response.write = "<select ...>" & vbcrlf
    response.write = "<option>" & join(S, "</option>" & vbcrlf & "<option>" ) & "</option>" & vbcrlf
    response.write = "</select>" & vbcrlf


     'clear array from memory (if you want to free up memory right away)


    erase S

  2. 01 Jan 1999 at 00:00

    This thread is for discussions of String Concatenation Component.

Leave a comment

Sign in or Join us (it's free).

Michael Balloni

Want to stay in touch with what's going on? Follow us on twitter!