UnderscoreJS Interpolation Regex that supports both mustache and original?

I regret going mustache-style underscore template interpolation because it conflicts with my django templates.

I'd like to start moving towards using the default interpolation settings moving forward without breaking existing code.

Can I get _ to respect two interpolation regexes without explicitly toggling between them?

The mustache regex: /\{\{(.+?)\}\}/g

I've tried matching the original + mustache to no success.

/(?:\{\{(.+?)\}\})|(?:\<\%\=(.+?)\%\>)/g

My shoddy regex skills prevents me from figuring out whether this is possible or not.

Upvotes: 2

Views: 1032

Answers (1)

mu is too short
mu is too short

Reputation: 434685

If you look at the _.template implementation, you'll see the root of your problem:

_.template = function(text, data, settings) {
  //...
  // Combine delimiters into one regular expression via alternation.
  var matcher = new RegExp([
    (settings.escape || noMatch).source,
    (settings.interpolate || noMatch).source,
    (settings.evaluate || noMatch).source
  ].join('|') + '|$', 'g');
  //...
  text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {

So _.template expects each of the three template delimiter expressions to contain exactly one capture group; the noMatch placeholder is just /(.)^/ so it won't match anything but it still contains the requisite capture group. Your attempt contains two capture groups as indicated:

/(?:\{\{(.+?)\}\})|(?:\<\%\=(.+?)\%\>)/g
//       ^^^                 ^^^

The second <%=...%> group is behind your troubles.

You can probably get away with this:

/(?:\{\{|<%=)(.+?)(?:%>|\}\})/g

But that will see things like <%= pancakes}} and {{pancakes %> as template expressions. I don't think you'll have to worry about things like that though.

That said, you should be able to automatically update your templates to your preferred style with some pretty simple regex work, just send all your templates through your favorite tool's version of:

s/\{\{(.+?)\}\}/<%= $1 %>/g

In JavaScript you'd have:

// read your template into old_school
new_school = old_school.replace(/\{\{(.+?)\}\}/g, '<%= $1 %>');
// replace your template with the content of new_school

Then you wouldn't have to worry about the funky regex above or having two sets of delimiters.

Upvotes: 3

Related Questions