akinuri
akinuri

Reputation: 12027

Regex as switch case

I have a song lyrics and I'm using a function to highlight the parts of the lyrics. The code looks like this:

var span        = {
    intro           : '<span style="color: Magenta ;">',
    verse           : '<span style="color: DodgerBlue;">',
    prechorus       : '<span style="color: DeepPink;">',
    chorus          : '<span style="color: Tomato;">',
    bridge          : '<span style="color: LimeGreen;">',
    outro           : '<span style="color: Magenta ;">',
    repeat          : '<span style="color: Silver;" title="Repeat">',
    close           : '</span>',
};

function highlight(lyrics) {
    var highlighted = lyrics.replace(/\[.*\]/g, function(match) {
        switch(match) {
            case "[Intro]":         return span.io              + match + span.close;   break;
            case "[Verse 1]":       return span.verse           + match + span.close;   break;
            case "[Verse 2]":       return span.verse           + match + span.close;   break;
            case "[Verse 3]":       return span.verse           + match + span.close;   break;
            case "[Verse 4]":       return span.verse           + match + span.close;   break;
            case "[Verse 5]":       return span.verse           + match + span.close;   break;
            case "[Pre-Chorus 1]":  return span.prechorus       + match + span.close;   break;
            case "[Pre-Chorus 2]":  return span.prechorus       + match + span.close;   break;
            case "[Pre-Chorus 3]":  return span.prechorus       + match + span.close;   break;
            case "[Pre-Chorus 4]":  return span.prechorus       + match + span.close;   break;
            case "[Chorus 1]":      return span.chorus          + match + span.close;   break;
            case "[Chorus 2]":      return span.chorus          + match + span.close;   break;
            case "[Chorus 3]":      return span.chorus          + match + span.close;   break;
            case "[Chorus 4]":      return span.chorus          + match + span.close;   break;
            case "[Chorus 5]":      return span.chorus          + match + span.close;   break;
            case "[Bridge 1]":      return span.bridge          + match + span.close;   break;
            case "[Bridge 2]":      return span.bridge          + match + span.close;   break;
            case "[Outro]":         return span.io              + match + span.close;   break;
        }
    });
    return highlighted.replace(/\(R.{0,3}\)/g, span.repeat + "$&" + span.close);
}

highlight function expects a text. First, it finds the strings (headers of lyrics parts) that are enclosed by brackets, then using switch, it checks the found matches and wraps them in a corresponding span tag.

My problem is that I don't want to use five different cases to replace verses, or any other repeating headers. Instead I want to use a regexp. Something like:

case /\[Verse.*?\]/g: return span.verse + match + span.close; break;

Fiddle

Upvotes: 3

Views: 2985

Answers (6)

Cory Robinson
Cory Robinson

Reputation: 5272

switch (myVar) {
   case 'case1':
      /...do work
      break
   case /[a-z]*/.test(myVar) && myVar:
      /...regex match, do work
      break
}

Upvotes: 0

c-smile
c-smile

Reputation: 27470

I would do it as

var html = format( s ,
  /\[Verse.*?\]/g,      "<span style='color: limegreen;'>@</span>",
  /\[Pre-Chorus.*?\]/g, "<span style='color: Magenta;'>@</span>",
  /\[Chorus.*?\]/g,     "<span style='color: DeepPink;'>@</span>"
 );

where format() is as simple as

function format(s) {
    for( var i = 1; i < arguments.length; i += 2 )
      if( var m = s.match( arguments[ i ] ) )
        return arguments[ i + 1 ].replace("@", m[ 1 ]);
    return "";
 }

The above is not tested but idea should be clear I think.

Upvotes: 0

brianary
brianary

Reputation: 9332

You may not need a case statement or even a lookup object here.

If you could modify the CSS or provide your own to change the selectors and move the inline styles into the CSS (where they really belong anyway), you could drastically simplify to:

function highlight(lyrics) {
    return lyrics.replace(/(\[([-a-z]+\b)(?: \d)?\])/gi,'<span class="$2">$1</span>');
}

You can tighten up the regex as neccessary if A-Z and dash happen to catch too much.

You could use a callback function similar to this replacement string if you want all-lowercase class names, want to coalesce the intro and outro into a single class, or remove dashes from the class names.

Upvotes: 1

Miguel
Miguel

Reputation: 20633

Use an object holding the regular expressions, instead of a switch statement.

var highlighted = lyrics.replace(/\[.*\]/g, function (match) {

    var regex = {
        intro: /\[Intro.*?\]/g,
        verse: /\[Verse.*?\]/g,
        prechorus: /\[Pre-Chorus.*?\]/g,
        chorus: /\[Chorus.*?\]/g,
        bridge: /\[Bridge.*?\]/g,
        outro: /\[Outro.*?\]/g
    };

    for (var k in regex) {
        if (regex.hasOwnProperty(k)) {
            if (regex[k].test(match)) {
                return span[k] + match + span.close;
            }

        }
    }

});

JSFiddle example

http://jsfiddle.net/unwthvns/1/

Switch statements can usually always be replaced with an object in JavaScript. No need for them.

Upvotes: 4

Reggie
Reggie

Reputation: 523

You could also use the string match method. This would have each case match the header against a regex. If the header does not match the regex, the case will fail and move on. For example:

case header.match(/\[Verse.*?\]/): return ...

Check out this post for some examples of how to use regular expressions in switch cases.

Upvotes: 1

Felix Kling
Felix Kling

Reputation: 816770

You can simply let the case fall through:

case "[Verse 1]":
case "[Verse 2]":
case "[Verse 3]":
case "[Verse 4]":
case "[Verse 5]": return span.verse + match + span.close; break;

or you have to use an if...else statement.

case values can be any expression, but the result is compared using strict comparison with the value passed to the switch statement, so you'd end up doing /\[Verse.*?\]/g === match.

Upvotes: 0

Related Questions