Reputation: 119
I am trying to add square brackets around chords in standard text documents formatted for guitar/lyrics to make them more compatible with the OnSong app. I have the rules but don't understand how to match for all the possible combinations. The rules are:
A couple notes: This is for a helper script... perfection is not needed. I do this by hand right now, so the occasional miss is okay. I'm not trying to parse out the details of the chords, just to wrap them in []. While the standard layout is 1 row of chords, 1 row of lyrics, this can't be counted on, so I'm aware some scenarios will fail occasionally.
Test source (chords are random for testing purposes, in case any musicians were going to chime in on the terrible music):
Db Dsus4/F# A Cbmin/C
A man can't be asked for that much to do
D/F# G A D#/E
And I can't sweep you off of your feet
Should turn into:
[Db] [Dsus4/F#] [A] [Cbmin/C]
A man can't be asked for that much to do
[D/F#] [G] [A] [D#/E]
And I can't sweep you off of your feet
My first attempt got me close with:
([A-G]((?!\s).)*)
but that picked up words that began with those letters as well. I have gone around in circles now and only gotten as far as:
\b([CDEFGAB](#|##|b|bb|sus|maj|min|aug)?\b)
When I've tried to use [^\s+]
I get mixed results that pick up more of what I want but also ditch things I need. I think I'm just over my head. Any help would be GREATLY appreciated and any explanation of how it works would be even better. While I'd like a solution, I'd also really love to explain why it works...
Upvotes: 7
Views: 2261
Reputation: 332
Check this out:
/([A-G](#|b)?)(\(?(M|maj|major|m|min|minor|dim|sus|dom|aug)?(\+|-|add)?\d*\)?)(\/([A-G](#|b)?))?/g
I've took it from chord-transposer:
var XRegExp = require("xregexp");
// Chromatic scale starting from C using flats only.
var FLAT_SCALE = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "Cb"];
// Chromatic scale starting from C using sharps only.
var SHARP_SCALE = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
// Regex for recognizing chords
var ROOT_PATTERN = '(?<root>[A-G](#|b)?)';
var SUFFIX_PATTERN = '(?<suffix>\\(?(M|maj|major|m|min|minor|dim|sus|dom|aug)?(\\+|-|add)?\\d*\\)?)';
var BASS_PATTERN = '(\\/(?<bass>[A-G](#|b)?))?';
var MINOR_PATTERN = '(m|min|minor)+';
var CHORD_REGEX = XRegExp("^" + ROOT_PATTERN + SUFFIX_PATTERN + BASS_PATTERN + "$");
and then
console.log(CHORD_REGEX); // will output regexp mentioned at the beginning of the answer
It works great for me.
Upvotes: 3
Reputation: 200
I have improved a little bit the answer from previous answer to help in my case. Now It was ignoring some "chords likely" when it is in the beginning of the verse (like A, E). This what I came out:
(\(*[CDEFGAB](?:b|bb)*(?:#|##|sus|maj|min|aug|m|M|°|[0-9])*[\(]?[\d\/]*[\)]?(?:[CDEFGAB](?:b|bb)*(?:#|##|sus|maj|min|aug|m|M|°|[0-9])*[\d\/]*)*\)*)(?=[\s|$])(?! [a-z])
Upvotes: 4
Reputation: 425063
This passes using your sample input and achieves all your "super bonus points" requirements:
String output = input.replaceAll("(?m)(^| )([A-G](##?|bb?)?((sus|maj|min|aug|dim)\\d?)?(/[A-G](##?|bb?)?)?)( (?!\\w)|$)", "[$2]");
This code turns this (as a single String with embedded line fees):
Db Dsus4/F# A Cbmin/C
A man can't be asked for that much to do
D/F# G A D#/E
And I can't sweep you off of your feet
Into this:
[Db] [Dsus4/F#] [A] [Cbmin/C]
A man can't be asked for that much to do
[D/F#] [G] [A] [D#/E]
And I can't sweep you off of your feet
Upvotes: 7
Reputation: 151
the code executes the agreement well in the sample I checked and Agreements simplesles 7th agreements with sharp or flat like C # 7
string strRegex = @"^[A-G]([5679bm#]([57])?|1[13]|6\/9|7[-#+b][59]|7?sus[24]|add[249]|aug|dim7?|m\/maj7|m1[13]|m[679]|m7?b5|maj1[13]|maj[79])?([\/][A-G]([5679bm#])?([57])?)?";
Regex myRegex = new Regex(strRegex, RegexOptions.None);
string strTargetString = @"A";
string strReplace = @"[$0]";
return myRegex.Replace(strTargetString, strReplace);
Upvotes: 0
Reputation: 626929
I have some working regex for the case you provided, but not sure how it will work for others. The problem is that a line can start with A
, or it can be in the song line. I tried to work around it using the negative lookahead checking if the chord is followed by a space and an alphanumeric. If there is a space and an alphanumeric, we do not match this chord. Since the chords can repeat after /
, I am doubling the pattern.
\b([CDEFGAB](?:b|bb)*(?:#|##|sus|maj|min|aug)*[\d\/]*(?:[CDEFGAB](?:b|bb)*(?:#|##|sus|maj|min|aug)*[\d\/]*)*)(?=\s|$)(?! \w)
Have a look at the demo.
Upvotes: 3