Using String Interpolation in JS for Cleaner, More Readable Code

I have been working on a project targeting modern browsers (Firefox and Chrome) and one of the primary purposes of this software is text analysis. In order to properly and most efficiently accomplish what I need to, I need to use loads of regular expressions.

But regular expressions can become quite cumbersome when you need to insert dynamic data into the patterns. It is one thing to replace a static value, but it is quite different when you are dealing with dynamic values. For example, let's say we needed to replace any a in a string with a b. That is simple to do:

var myText = 'My name is Ryan (isn\'t this exciting!) and I am not an islander.';
myText = myText.replace(/a/gi, 'b');

// My nbme is Rybn (isn't this exciting!) bnd I bm not bn islbnder.

But now imagine that we can't statically program in the letter to be replaced. It needs to be dynamically inserted. In that case, we can no longer use a regular expression literal. Now we need to construct the regex from a string.

var myText = 'My name is Ryan (isn't this exciting!) and I am not an islander.';
var strToReplace = 'a';

var myPatt = new RegExp(strToReplace, 'gi');
myText = myText.replace(myPatt, 'b');

// My nbme is Rybn (isn't this exciting!) bnd I bm not bn islbnder.

Ok, so now we are constructing the regular expression with a passed-in string. In this case I used the letter a, but it could be anything. It is still pretty simple (though obviously not very useful!). So now let's begin adding complexity.

The problem!

Let's say that I want to replace all instances of the word is in the sentence with the word was. If I used my pattern from above, I would have a problem.

var myText = 'My name is Ryan (isn\'t this exciting!) and I am not an islander.';
var strToReplace = 'is';

var myPatt = new RegExp(strToReplace, 'gi');
myText = myText.replace(myPatt, 'was');

// My name was Ryan (wasn't thwas exciting!) and I am not an waslander.

So, you can see the problem here. I wanted to replace all instances of the word is, but using this simple pattern I ended up replacing all instances of is in the string. That is not what we want.

At this point we have a few options. If we were working in English, the easiest would be to change the regex pattern to make sure the that it only finds is when it is surrounded by non-word characters (something that is not a-z or 0-9). But you will notice that my pattern is starting to get ugly.

var myText = 'My name is Ryan (isn\'t this exciting!) and I am not an islander.';
var strToReplace = 'is';

var myPatt = new RegExp('(^|\\W)' + strToReplace + '(?!\\w)', 'gi');
myText = myText.replace(myPatt, '$1was');

// My name was Ryan (isn't this exciting!) and I am not an islander.

My pattern now looks for any is as long as it is preceeded by a non-word character and followed by something other than a word character. But in the application I am building, the languages do not fit into these categories, so I have to make my own lists of word characters. Once I have to pass in as strings my own word characters, the pattern really begins getting out of hand.

var myText = 'My name is Ryan (isn\'t this exciting!) and I am not an islander.';
var strToReplace = 'is';

var wordChs = 'abcdefghijklmnopqrstuvwxyz';

var myPatt = new RegExp('(^|[^' + wordChs + '])' + strToReplace + '(?![' + wordChs + '])', 'gi');
myText = myText.replace(myPatt, '$1was');

// My name was Ryan (isn't this exciting!) and I am not an islander.

In this example I am not even taking into account morpheme markers or diacritical marks, yet it is already getting out of hand with all of the concatenation. That is not a nice way to build patterns from strings!

Here is where string interpolation comes in. In Javascript we have a new string type called Template Strings which allow us to build strings using interpolation rather than concatenation. There are other benefits to these strings, most clearly being that you can make multi-line strings (e.g. for HTML blocks), but those are not what I am focusing on here.

The solution!

String interpolation allows us to build our strings in a much cleaner way, and for this example it will help make our regex pattern string more clear and readable. Traditionally, in JS, if you wanted to join strings you would need to concatenate them with a +. For example:

var name = 'Ryan';
var sentence = 'Hi! My name is ' + name + '!';

// Hi! My name is Ryan!

String interpolation allows you to get rid of the + signs. First, for template strings you wrap your string in tick ` marks rather than the traditional single or double quotes. Then, you just put a ${} containing an expression or variable into the string. For example:

var name = 'Ryan';
var sentence = `Hi! My name is ${name}!`;

// Hi! My name is Ryan!

At first, this might not seem that special. But if you are like me and build regular expressions from strings on a daily basis, THIS IS HUGE! Let's take our example from above and change it to use string interpolation rather than concatenation. Notice how much more clean and readable it is.

var myText = 'My name is Ryan (isn\'t this exciting!) and I am not an islander.';
var strToReplace = 'is';

var wordChs = 'abcdefghijklmnopqrstuvwxyz';

var myPatt = new RegExp(`(^|[^${wordChs}])${strToReplace}(?![${wordChs}])`, 'gi');
myText = myText.replace(myPatt, '$1was');

// My name was Ryan (isn't this exciting!) and I am not an islander.

Conclusion

So, there you have it. Template strings are a welcome addition to JavaScript for me and I can only assume many other JS developers. Unfortunately, you can only use them in Firefox or Chrome at the moment (they also work in io.js, but not yet in Node), but luckily in my case we are only targeting those browsers! And for those who are under different constraints, hopefully support will come soon to the other browsers. This feature has been in other languages for a long time and I am glad JavaScript is finally catching up.

To see this code in action, visit: https://jsfiddle.net/ryanburgett/htndqvu0/3/.