Reputation: 23
How to make one pattern string for preg_match_all()
function If I have multiple strings to match like "G,C,D"
& "A,B,C"
& "E,C,D"
Currently my string is
$str = "/(?<=\b)([CDEFGAB](?:b|bb|m)*(?:#|##|sus|maj|min|aug)*[\d\/]*(?:[CDEFGAB](?:b|bb|m)*(?:#|##|sus|maj|min|aug)*[\d\/]*)*)(?=\s|$|(<.*>))(?! \w)/"
preg_match_all($str,$lyrics , $output_array);
I want to add these combinations ("G,C,D" & "A,B,C" & "E,C,D")
in $str
string.
Upvotes: 2
Views: 269
Reputation: 4035
NOTE this answer has been dramatically edited over time to arrive at this final conclusion.
by referring to this site: http://www.all-guitar-chords.com/ i came up with this regular expression:
\b(?:G,C,D|A,B,C|E,C,D)|(?:[ABCDEFG](?:#|b)?)(?:\/[ABCDEFG]b)?(?:(?:(?:maj|min|sus|add|aug|dim)(?:\d{0,2}(?:#\d{1,2}|sus\d)?)?)|(?:m\d{0,2}(?:(?:maj|add|#)\d{0,2})?)|(?:-?\d{0,2}(?:\([^)]*\)|#\d{1,2})?))?)
<?php preg_match_all( '`' . $reg_exp . '`', $str, $matches ); ?>
my final expression does NOT capture any backreferences. therefore, $matches[0]
will be an array of the matches (because the zero-index array is always an array of the full strings that matched the full expression and subsequent arrays will refer to backreferences, if any).
it was written with as much precision as possible, but this expression could still return false positives, although very unlikely.
the only other way to do this is to use an array of each of the possible chords you are interested in. then iterate that array searching for each string explicitly -- and that would still be prone to false positives.
here is a site to tinker with it: https://regex101.com/r/vW9sJ2/7
NOTE the original question by the OP was how to add certain string combinations into the expression such as "G,C,D" or "A,B,C" (examples given by the OP). however, the musicians i spoke with said they couldn't see how extracting the chord combinations would be helpful as there are so many variations. they weren't even sure how extracting chords like this would help at all. which makes me curious as to what the OP intends to use this for and i hope he can explain for me (especially seeing how much time i spent on this given my obsessesive nature, lol).
EDIT without reply from the OP, not sure if this fulfills the OPs needs, and i've begun to wonder if he needs a more flexible match for the combinations (ex: G,C,D). so i've modified the expression to handle that:
\b(?:[ABCDEFG],[ABCDEFG],[ABCDEFG])\b|(?:[ABCDEFG](?:#|b)?)(?:\/[ABCDEFG]b)?(?:(?:(?:maj|min|sus|add|aug|dim)(?:\d{0,2}(?:#\d{1,2}|sus\d)?)?)|(?:m\d{0,2}(?:(?:maj|add|#)\d{0,2})?)|(?:-?\d{0,2}(?:\([^)]*\)|#\d{1,2})?))?)
and the fiddle for that: https://regex101.com/r/vW9sJ2/7
Upvotes: 1
Reputation: 626748
Here is a way to match your G,C,D-like strings:
\b
(?:(?:[CDEFGAB]
(?:b|bb|m)*
(?:\#|\#\#|sus|maj|min|aug)*
[\d\/]*
(?:[CDEFGAB]
(?:b|bb|m)*
(?:\#|\#\#|sus|maj|min|aug)*
[\d\/]*
)*
),?)+
(?=\s|$|(?:<.*>))
(?![[:blank:]]\w)
Or as a one-liner:
\b(?:(?:[CDEFGAB](?:b|bb|m)*(?:\#|\#\#|sus|maj|min|aug)*[\d\/]*(?:[CDEFGAB](?:b|bb|m)*(?:\#|\#\#|sus|maj|min|aug)*[\d\/]*)*),?)+(?=\s|$|(?:<.*>))(?![[:blank:]]\w)
Upvotes: 1