String Concatenation Tricks

Massive string concatenation isn't used all that often in CF, but it's sometimes needed. My most common use is probably creating text-only emails. You can do it with the output stream directly, but you usually run into problems with an extra line break here or there, because of the way your CF tags are laid out. But if you try and correct the formatting in the output, you end up with CF code that is horribly jumbled. The solution is doing string concatenation within a variable, but it has some downsides as well: it can be cumbersome, can be hard to follow, and for large strings can be relatively slow (because of the way Java optimizes strings).

Java, however, provides some classes that can make this process a lot easier. The simplest one is java.lang.StringBuffer. Here's an example:

<cfscript>
sb = createObject("java", "java.lang.StringBuffer").init();
sb.append("my text" & chr(10));
sb.append("my other text" & chr(10));
if (1 EQ 2)
  sb.append("never happen" & chr(10));
myTextString = sb.toString();
</cfscript>

As you can see, there's not "myTextString = myTextString & " repeated all over the place, which makes the code easier to follow. However, you still have to deal with the carriage returns, but we can solve that problem too. Now we're going to use two classes from the java.io package: StringWriter and PrintWriter. Here's the example:

<cfscript>
sw = createObject("java", "java.io.StringWriter").init();
out = createObject("java", "java.io.PrintWriter").init(sw);
out.println("my text");
out.println("my other text");
if (1 EQ 2)
  out.println("never happen");
myTextString = sw.toString();
</cfscript>

We're using the println method, which prints the supplied text, along with a newline (and/or carriage return) character. You can also use the print method to print some text without adding a newline.

In both cases, mixing logic into the string generation code is simplified, because whitespace in the program code itself is irrelevant, just like normal concatenation, but we're stripping out some of the nastiness that concatenation brings. In the latter example, we take it a step further by using some of Java's built-in classes to help take care of the nasty work (dealing with newlines).

Just as an aside, this is a prime example of both the Adapter and Decorator design patterns. The StringWriter adapts a StringBuffer for writing to, rather than string manipulations. Note that you don't see the StringBuffer in the second example, it's internal to the StringWriter instance. Then the PrintWriter decorates the StringWriter to supply additional methods to make using it easier (namely print and println).

3 responses to “String Concatenation Tricks”

  1. stylo~

    Thanks for this. But doessn't it need to be CHR(13)& CHR(10)? If so… ?

  2. stylo~

    What would we do without google? Just found it after posting:

    * Windows (\r\n): #chr(13)##chr(10)#
    * Unix (\n): #chr(10)#
    * MacOS 9 and earlier (\r): #chr(13)#

    So, are we covered on windows with the java class?

  3. barneyb

    The Java class will use the appropriate line endings for the platform you are running on. Note, however, that's the server platform, not the client platform. So if you're running Linux servers and a windows user connects, it's the Linux line ending that's used. In general, this doesn't matter (Notepad is the only Windows program I've run across that doesn't process Unix line endings properly), but it's something to consider. If you do need to do cross-platform generation, then you have to use the first method, and select the appropriate line ending based on CGI variables (or whatever).