Reputation: 89
I want to achieve the following:
1) Check if every word (in this case guitar chord) from a text line is contained in RegEx. All words/characters must match.
2) If yes, I want every single word from that line to become a link, pointing to an URL customized by the word itself.
I.E. The following line:
Am Bb C# Dadd9
Song lyrics here
should become this:
<a href="example.com/Am">Am</a> <a href="example.com/Bb">Bb</a> <a href="example.com/C#">C#</a> <a href="example.com/Dadd9">Dadd9</a>
Song lyrics here
My RegEx (notes and symbols forming each chord):
var lineRegex = /^\s*(?:(A|B|C|D|E|F|G|A#|C#|D#|F#|G#|Ab|Bb|Db|Eb|Gb){1}(?:m|\+|\-|aug|dim|add|b|#|1|2|3|4|5|6|7|8|9|0|\/)*\s*)+$/;
Here's what I've com up to for step 2:
var text = $('.input').val(); //get text
var lines = text.split('\n'); //split text into lines
var chords = lines.split(' '); //split lines into chords
var link = "http://www.example.com/";
$.each(chords, function(index, value) { //append link to chord
$('.output').append('<a href="' + link + value + '">' + value + '</a> ');
});
I can't achieve step 1. How do I check if a text line contains only notes and symbols from RegEx?
Upvotes: 1
Views: 1862
Reputation: 22817
I have no idea what chords are valid/invalid on a guitar, and since you haven't specified that information (in clear text - without implemented regex), and we aren't certain that your regex works, I'm basing my answer off of this random chart I found (first result on Google images for list of all guitar chords).
Based on this chart, I've created the following regex
(?(DEFINE)
(?<chord_A>A(?:b(?:[679+]|sus)?|m[67]?|[689]|maj7|dim|\+|sus)?)
(?<chord_B>B(?:b(?:[679+]|sus|m[67]?|maj7|dim)?|m[67]?|[679+]|maj7|dim|sus)?)
(?<chord_C>C(?:[679+]|m[67]?|maj7|dim|sus|\#(?:m[67]?|dim))?)
(?<chord_D>D(?:b(?:[679+]|maj7|sus)?|[679]|m[67]?|maj7|dim|\+|sus)?)
(?<chord_E>E(?:b(?:[679+]|sus|m[67]?|maj7|dim)?|m[67]?|[679+]|maj7|dim|sus)?)
(?<chord_F>F(?:[679+]|m[67]?|maj7|dim|sus|\#(?:[79]|m[67]|dim)?)?)
(?<chord_G>G(?:b(?:maj7|sus|[6+])?|[679+]|m[67]?|maj7|dim|sus|\#(?:m[67]?|dim))?)
(?<chords>(?&chord_A)|(?&chord_B)|(?&chord_C)|(?&chord_D)|(?&chord_E)|(?&chord_F))
)
(?<link>\b(?&chords)(?=\s|$))
In this regex, I've defined groups according to chords' starting letter (e.g. A
).
This regex works by defining all possible instances of each chord (in each group chord_X
where X
represents the chord, i.e. C
). The defined group chords
is a comparison between each chord (e.g. Chord A
or Chord B
or ...). The final regex uses (?<link>\b(?&chords)(?=\s|$))
. This regex ensures that a word boundary character exists before the chord (each begins with a letter so this will not fail), and is followed by either a space or the end of the string
$
(\b
cannot be used here since some notes include word boundary characters - such as #
, thus, to properly catch these instances, we use spaces or EOF).
Note that since C#
doesn't exist in the image (unless I'm blind), it won't catch C#
from your input. You can change this behaviour by using the following regex instead (which just adds a ?
at the end of \#(?:m[67]?|dim)
in the chord_C
defined group.
(?(DEFINE)
(?<chord_A>A(?:b(?:[679+]|sus)?|m[67]?|[689]|maj7|dim|\+|sus)?)
(?<chord_B>B(?:b(?:[679+]|sus|m[67]?|maj7|dim)?|m[67]?|[679+]|maj7|dim|sus)?)
(?<chord_C>C(?:[679+]|m[67]?|maj7|dim|sus|\#(?:m[67]?|dim)?)?)
(?<chord_D>D(?:b(?:[679+]|maj7|sus)?|[679]|m[67]?|maj7|dim|\+|sus)?)
(?<chord_E>E(?:b(?:[679+]|sus|m[67]?|maj7|dim)?|m[67]?|[679+]|maj7|dim|sus)?)
(?<chord_F>F(?:[679+]|m[67]?|maj7|dim|sus|\#(?:[79]|m[67]|dim)?)?)
(?<chord_G>G(?:b(?:maj7|sus|[6+])?|[679+]|m[67]?|maj7|dim|sus|\#(?:m[67]?|dim))?)
(?<chords>(?&chord_A)|(?&chord_B)|(?&chord_C)|(?&chord_D)|(?&chord_E)|(?&chord_F))
)
(?<link>\b(?&chords)(?=\s|$))
<a href="example.com/${link}">${link}</a>
The substitution makes reference to the named capture group from our regex link
.
Am Bb C# Dadd9
Song lyrics here
<a href="example.com/Am">Am</a> <a href="example.com/Bb">Bb</a> C# Dadd9
Song lyrics here
<a href="example.com/Am">Am</a> <a href="example.com/Bb">Bb</a> <a href="example.com/C#">C#</a> Dadd9
Song lyrics here
Since javascript doesn't use PCRE regex, you can't use named capture groups as the above suggests, so, unfortunately, we're going to have to use a beautiful long and unreadable regex as follows...
(\b(?:(?:A(?:b(?:[679+]|sus)?|m[67]?|[689]|maj7|dim|\+|sus)?)|(?:B(?:b(?:[679+]|sus|m[67]?|maj7|dim)?|m[67]?|[679+]|maj7|dim|sus)?)|(?:C(?:[679+]|m[67]?|maj7|dim|sus|\#(?:m[67]?|dim)?)?)|(?:D(?:b(?:[679+]|maj7|sus)?|[679]|m[67]?|maj7|dim|\+|sus)?)|(?:E(?:b(?:[679+]|sus|m[67]?|maj7|dim)?|m[67]?|[679+]|maj7|dim|sus)?)|(?:F(?:[679+]|m[67]?|maj7|dim|sus|\#(?:[79]|m[67]|dim)?)?)|(?:G(?:b(?:maj7|sus|[6+])?|[679+]|m[67]?|maj7|dim|sus|\#(?:m[67]?|dim))?))(?=\s|$))
With <a href="example.com/$1">$1</a>
as the substitution.
Upvotes: 2