More fun with strings: dojo.string.contains()

In the series “convenience wrappers for small tasks that increase code readability”, today contains() is starring. Having a contains() method could also serve another purpose: to maybe prevent people from using match() to find out if a string contains a given substring (what is still proposed in some JS tutorials out there…). So, I want the contains() method to also have a switch to work case-insensitive.

Besides indexOf(), there are some other ways to achieve this, so – let’s have a competition and find out who’s the fastest!

The Contestants

replace and length

One possibility is to replace the searched string with an empty string, read the length property of the modified string and compare it to the length of the haystack. If it’s different, the haystack contains the needle. Reading the length property is extra work, but comparing two integers is faster than comparing two strings, so maybe it’s faster in general.

replace

Again, replace the searched string with an empty string. Then compare the the modified string with the haystack. If they are different, the haystack contains the needle.

split

Take the haystack and try to split it using the needle as the seperator. If the result’s length is greater than one, the haystack contains the needle.

indexOf

Find the first occurance of needle in haystack; if the result is something else than -1, the haystack contains the needle.

Results

For testing, I did 10,000 iterations and retrieved the execution time in ms. The methods were tested in the order presented above.

On Chromium (Mac build, Version 4.0.203.0 here), replace + length is slightly faster than replace, and both are faster than split. indexOf is by far the fastest.

1) true: 7 / false: 3.5
2) true: 7.5 / false: 3.5
3) true: 10 / false: 8
4) true: 2.5 / false: 3

Safari 4 has nearly the same results as Chromium, but the numbers tend to differ a lot from test to test.

1) true: 4-18, avg 10 / false: 2.5
2) true: 4-19, avg 10 / false: 3
3) true: 6-22. avg 13 / false: 6-23 avg. 16
4) true: 2 / false: 3

On Firefox 3.5, split a bit faster than the two replace methods, but indexOf is again by far the fastest.

1) true: 13 / false 10
2) true: 13 / false 10
3) true: 10 / false 9
4) true: 1.5 / false: 2

On IE 8 (run in a VM), both replace versions perform almost the same, and faster than split. Again, indexOf is fastest. Only 2 – 3 times faster than the replace methods, but still the fastest.

1) true: 35 / false: 25
2) true: 30 / false: 25
3) true: 60 / false: 50
4) true: 15 / false: 15

You can run the tests yourself, if you are interested, the test page is here.

Summary

The results are pretty obvious: indexOf() outperforms the other contestants. Which is not really a surprise, considering that whatever Javascript does during indexOf() –  it has also to do the same before being able to do a split() or replace(). So, the proposed way for a contains() method is the following:

dojo.string.contains = function(/* string */ needle, /* string */ haystack, /* bool */ caseInsensitive) {
    if(caseInsensitive) {
        needle = needle.toLowerCase();
        haystack = haystack.toLowerCase();
    }
    return haystack.indexOf(needle) !== -1;
}

If you want to use contains() in your code, just copy the above lines somewhere in your code. Again, don’t forget to dojo.require(“dojo.string”) before.

Or, if you want to have beginsWith(), endsWith() and contains() all-in-one, use this: dojo.string.addons.js

[Comments are automatically closed after 30 days.]

Comment via Google+