Reputation: 12027
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;
Upvotes: 3
Views: 2985
Reputation: 5272
switch (myVar) {
case 'case1':
/...do work
break
case /[a-z]*/.test(myVar) && myVar:
/...regex match, do work
break
}
Upvotes: 0
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
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
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
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
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