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
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
Share Improve this question edited Aug 16, 2014 at 2:36 akinuri asked Aug 15, 2014 at 23:13 akinuriakinuri 12.1k10 gold badges75 silver badges107 bronze badges 4- Is there a reason for using both CSS classes and inline styles? Do you not have access to the CSS, and a CSP blocks a custom CSS source? – brianary Commented Aug 16, 2014 at 1:03
- @brianary Nope. My mistake. That is an old script. I used to use CSS to style the headers. Not anymore. I forgot to remove them. Updated the question. – akinuri Commented Aug 16, 2014 at 1:11
- This gets much easier if you can move the inline CSS into a stylesheet, or even programmatically add the styles. Inline styles are less efficient and maintainable anyway. – brianary Commented Aug 16, 2014 at 1:17
- Yea, I know. I'm planing to store the styles in an object and add them with JS. I'll do that once the application I'm working on is done. It's just that it's too easy to do, that I ignore it for now =) – akinuri Commented Aug 16, 2014 at 1:23
6 Answers
Reset to default 4Use 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/unwthvns/1/
Switch statements can usually always be replaced with an object in JavaScript. No need for them.
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.
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.
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 pared using strict parison with the value passed to the switch
statement, so you'd end up doing /\[Verse.*?\]/g === match
.
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.
switch (myVar) {
case 'case1':
/...do work
break
case /[a-z]*/.test(myVar) && myVar:
/...regex match, do work
break
}