Actionscript 3 Find and Replace String Performance Comparison
A library I use quite frequently in AS3 is as3corelib. This library was written by a few guys from Adobe and it provides an assortment of very useful AS3 classes. I recommend checking it out if you aren't already using it. If you've been under a rock, it has classes for encoding JPGs and PNGs. It has Array, Date, Dictionary, Int, Number, String, and XML utility classes. It has libraries for encoding and decoding JSON strings. Anyway, you get the point. I use the library often.
I did notice something the other day that I've been meaning to test. I finally got around to it this morning...
In the StringUtil class there is a replace() method that allows you to perform a find and replace on a string. The method signature looks like this:
public static function replace(input:String, replace:String, replaceWith:String):String
It looks simple enough. In fact, it may be a little easier to read than the way I've traditionally done find and replace. If I have this string, "The cow jumped over the moon," and I wanted to replace "moon" with "fence". In the past, I would have just written something like this:
var str:String = "The cow jumped over the moon."; var newStr:String = str.split("moon").join("fence");
Using this utility class, this would change to:
import com.adobe.utils.StringUtil; var str:String = "The cow jumped over the moon."; var newStr:String = StringUtil.replace(str, "moon", "fence");
While I was looking through the source code in the library, I noticed that the code for executing the replace is MUCH more involved than I expected. It looks like this:
public static function replace(input:String, replace:String, replaceWith:String):String { //change to StringBuilder var sb:String = new String(); var found:Boolean = false; var sLen:Number = input.length; var rLen:Number = replace.length; for (var i:Number = 0; i < sLen; i++) { if(input.charAt(i) == replace.charAt(0)) { found = true; for(var j:Number = 0; j < rLen; j++) { if(!(input.charAt(i + j) == replace.charAt(j))) { found = false; break; } } if(found) { sb += replaceWith; i = i + (rLen - 1); continue; } } sb += input.charAt(i); } //TODO : if the string is not found, should we return the original //string? return sb; }
Wow. Ok, so I thought there might be a performance advantage to going through all that mess to do a find and replace. So, I ran a couple of tests to see what happened.
First, I tested the old fashioned way:
import flash.utils.*; var str:String = "The cow jumped over the moon. " + "The cow jumped over the moon. " + "The cow jumped over the moon. " + "The cow jumped over the moon. "; trace("timer before loop: " + getTimer()); var i:int = 0 var len:int = 50000; for(i=0; i<len; i++) { str.split("moon").join("fence"); } trace("timer after loop: " + getTimer());
The output to the trace window was:
timer before loop: 3
timer after loop: 324
Then, I tested using the StringUtil class:
import com.adobe.utils.StringUtil; import flash.utils.*; var str:String = "The cow jumped over the moon. " + "The cow jumped over the moon. " + "The cow jumped over the moon. " + "The cow jumped over the moon. "; trace("timer before loop: " + getTimer()); var i:int = 0 var len:int = 50000; for(i=0; i<len; i++) { // str.split("moon").join("fence"); StringUtil.replace(str, "moon", "fence"); } trace("timer after loop: " + getTimer());
The output to the trace window was:
timer before loop: 4
timer after loop: 3145
Ouch! Now bear in mind, that I'm looping over this string 50,000 times so that we can magnify the comparison, but we definitely don't have a performance advantage by using the StringUtil class. In fact, it's almost 10 times faster using split/join!
I love the as3corelib library, but in this case, I think I'll stick to my old habits.
7 Responses
Will do. Thanks.
As a third comparison, I did some benchmarking of find/replace via regular expressions. You may have seen the native String method ‘replace()’:
myString.replace(pattern:*, repl:Object):String
This is an extremely powerful find and replace method allowing searches ignoring case, multiple group matches that can be used as parameters in the replace text, etc. (It’s all well documented in the Flash help).
In short i was able to do the same find and replace using regular expressions like this…
str.replace(/moon/g, “fence”);
The ‘g’ flag is important so that it replaces ALL matches of “moon” and not just the first one. You could also use the ‘i’ flag to perform a find/replace as case insensitive.
There are likely performance differences between our boxes, but here’s my results:
Split Join: ~475 ms
Regular Expressions: ~625 ms
I would consider that pretty small for the power that comes with it.
As a follow up, it takes ~175ms to create the previous instance of RegExp 50,000 times. So if it were possible to reuse the same RegExp instance, it could be marginally faster than the split/join.
Both of the following declarations are identical.
// This is the shorthand form
var regExp:RegExp = /moon/g;
// This is the full class form
var regExp:RegExp = new RegExp(”moon”, “g”);
You’re using quite a small string. I would try the replaces on much larger strings and see what kind of results you get. The two implementations may not have linear performance with respect to the length of the string.
fyi
This has been updated in the library:
http://code.google.com/p/as3corelib/issues/detail?id=87
thanks for the help…
mike chambers
Cool, thanks!


Thanks for doing the test. If you can log a bug with the issue (on the project page), then we can look at replacing the method with your code.
mike chambers
mesh@adobe.com