Skip to main content
Ben Nadel at cf.Objective() 2012 (Minneapolis, MN) with: Shawn Slaughter and Scott Stroz
Ben Nadel at cf.Objective() 2012 (Minneapolis, MN) with: Shawn Slaughter and Scott Stroz@boyzoid )

Referencing String Characters Using Array-Notation In ColdFusion 2021

By on
Tags:

A few years ago, I mentioned that you can treat Strings like character arrays in Lucee CFML. It turns out, you can do the same thing in Adobe ColdFusion. I am not sure what version this was added in; but, I'm guessing it was ColdFusion 2018 (and the introduction of "array slices"). To help burn this into my brain, I wanted to put together a quick demo.

In the following code, I'm demonstrating three distinct ColdFusion features:

  • References letters using index-based access.
  • Iterating over letters using a for-in loop.
  • Iterating over letters using member-methods (ex, .map() and .each()).
<cfscript>

	value = "hello world";

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	// Iterate over the characters in a string using array notation.
	runExample(
		() => {

			for ( var i = 1 ; i <= value.len() ; i++ ) {

				writeOutput( value[ i ] );

			}

		}
	);

	// Iterate over the characters in a string as if it were an array.
	runExample(
		() => {

			for ( var letter in value ) {

				writeOutput( letter );

			}

		}
	);

	// Iterate over the characters in a string using member methods.
	runExample(
		() => {

			var newValue = value.map(
				( letter ) => {

					return( ucase( letter ) );

				}
			);

			writeOutput( newValue );

		}
	);

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	/**
	* I invoke the given callback and then add a line-break.
	*/
	public void function runExample( required function callback ) {

		callback();
		writeOutput( "<br />" );

	}

</cfscript>

As you can see, in all three of these examples, I'm treating a String as if it were an Array. And, when we run this ColdFusion 2021 code, we get the following output:

hello world
hello world
HELLO WORLD

Here's something interesting, though: in my last example with ucase(), I tried to invoke that function as a member method on the character passed into the iteration operator (callback). But, it seems that .ucase() is not available as a member method in this context. This is likely a bug, but worth being aware of:

<cfscript>

	// Iteration using for-in.
	for ( letter in "A" ) {

		writeDump( letter.getClass().getName() );
		writeOutput( "<br />" );

		try {

			writeOutput( letter.lcase() );
			writeOutput( "<br />" );

		} catch ( any error ) {

			writeOutput( error.message );
			writeOutput( "<br />" );

		}

	}

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	// Iteration as a member method.
	"A".each(
		( letter ) => {

			writeDump( letter.getClass().getName() );
			writeOutput( "<br />" );

			try {

				writeOutput( letter.lcase() );

			} catch ( any error ) {

				writeOutput( error.message );

			}

		}
	);

</cfscript>

Here, I'm using two forms of iteration - for-in and member-method - and for each, I'm inspecting the underlying Java class of the given letter. And, when we run this in ColdFusion 2021, we get the following:

java.lang.String
a

java.lang.Character
The lcase method was not found.

As you can see, when using member-method iteration, the letter is actually a different class - java.lang.Character - which is why the .lcase() method in this case cannot be invoked as a member method. Again, this is likely a bug in the runtime.

A month ago, I talked about upgrading my blogging platform to Adobe ColdFusion 2021; and, I've already been able to leverage this new character-array functionality. I'm using it to generate cryptographically secure tokens using the randRange() function with the SHA1PRNG algorithm:

<cfscript>

	writeOutput( generateTokenValue( 20 ) );

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	/**
	* I generate a cryptographically secure random token with the given length.
	*/
	public string function generateTokenValue( numeric tokenLength = 200 ) {

		var letters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
		var letterCount = letters.len();
		var parts = [];

		for ( var i = 1 ; i <= tokenLength ; i++ ) {

			parts.append( letters[ randRange( 1, letterCount, "SHA1PRNG" ) ] );

		}

		return( parts.toList( "" ) );

	}

</cfscript>

Notice that I'm accessing the random letter using the letters[i] array-notation. And, when we run this ColdFusion template a few times, we get the following cryptographically secure random tokens:

  • RxMbzBOtUaWE2DJ8cL25
  • 8EDL7BOgQowrz3QLx8aI
  • KrJBzR6vx9BCkjAvEwmd
  • 7U8ILIQ7irbOQdXsXbOo

Again, I don't know when this String-as-character-array functionality was added to Adobe ColdFusion; but, I'm excited to finally be able to use it!

Want to use code from this post? Check out the license.

Reader Comments

45 Comments

Thanks as always for sharing your discoveries, Ben. As for this, yes, it's supported as of Cf2018 and up. Here's that last code running on trycf as 2018:

https://trycf.com/gist/75b3994be85aa042127e946905e29518/acf2018

and it fails if the url is changed to point to a cf2016. For some, that's all they need to see as the answer. (And I realize Ben is focused in these recent posts on just converting things to cf2021.)

For other folks, who may indeed wonder when something he points out may have changed in what engine version, I'd like to elaborate a bit to help them consider this approach to answering that question.

As surely Ben and many here know, trycf.com and cffiddle.org let you run (almost any) cfml, against different cf engine versions. They're (nearly) perfect for proving when such a change in language support happened.

Trycf.com supports CF 2021, 2018, 2016, 11, and even 10, as well as Lucee 5 and 4.5 and Railo 4.2, while Cffiddle.org, being from Adobe, supports CF 2021, 2018, and 2016. Each has its pros and cons, and I've been meaning to do a post on them, for those who may not know of either or both.

Of course, even for those who know of either, half the battle is remembering to try them in a case like this. :-) That's part of why I'm writing this. The other "half" of the battle (most of it) is having to create standalone code that can be used to test your question on either. Fortunately, the docs for CF and Lucee (and cfdocs.org) have largely been moving to using links to either of these showing running example code, to save us that trouble. Sometimes, that can be where we can easily see whether (or as of when) something we're interested in is supported.

In Ben's case, the last example can be seen running against cf2016 (where it fails) using this link:
https://trycf.com/gist/75b3994be85aa042127e946905e29518/acf2016

And the engine/version can be changed on that url or by using the gear icon in the trycf.com web ui. Again changing this to cf2018 (or 2021) shows that it works there. Yay. :-)

Hope that may help some folks. Again, I realize it's "obvious" to others. Since Ben's blog brings people together who have such wide ranges of experience, this seemed an opportune moment to mention the above.

15,192 Comments

@Charlie,

Great points all around. I have to say, I really like the fact that the Lucee CFML docs actually embed a TryCF iframe right in a lot of their function/tag pages. It's super helpful to see how things work.

Though, I have to admit that I usually use other people's TryCF examples - I am not good about creating my own. It's probably something I should look at doing more - it would make the examples palpable in a way they can't be with writing alone.

Post A Comment — I'd Love To Hear From You!

Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.