入力を制御できない場合(たとえば、タブ譜のWebサイトからこれらをスクレイピングしている場合)、何らかの理由でこれらのコードが行間ではなく単語間でインターリーブされていると仮定すると、次のようになります。
<?php
$mods = '(?:maj|m|min|sus|add9|aug|dim|dom|...)';
$regex = "/\b([ABCDEFG][#b]?$mods?)\s+/"
?>
恐れ入りますが、「次の2つのスペース」の制約がわかりません。ただし、コード「A」と単語「A」を区別しようとしている場合は、その方法に反対することをお勧めします。代わりに、完全にはほど遠いものの、次の代替ルールを検討してください。「A」は一般的にそれ自体が単語である唯一のコードです。したがって、歌詞が十分に大文字になっている場合、「A」がコードではなく単語であるというヒントは、次の単語が大文字でない単語であるということです。
Am B A plane came down C# --> Am B C#
Am B A Plane came down C# --> Am B A C#
あなたがそれについて考えるならば、文脈の手がかりは別として、これは人間も言うことができる方法です。この戦略から正規表現を作成するには、次のように、唯一の「A」を特殊なケースと見なします。
<?php
$mods = '(?:maj|m|min|sus|add9|aug|dim|dom|...)';
$regex_1 = '((?:A(?!\s)|[BCDEFG])[#b]?$mods?)';
$regex_2 = '(A(?=\s+[a-z]))';
$regex = "/\b(?:$regex_1|$regex_2)\s+/";
?>
ここで実行中のデモを参照してください:http://rubular.com/r/tRjozL7KCx。
これは完璧にはほど遠いですが、最初から改善できるものです。
更新:学習に役立つ説明。
\b A word-boundary, so "A plane came down and CRASHED
into the sea" will not match "D" as a note.
(?: A non-capture group. (Ignore this for now.)
( A capture group. (To encapsulate $regex_1.)
(?: A non-capture group. (Ignore this for now.)
A(?!\s) An "A" not followed by whitespace, i.e. a "lone A".
| An "OR" operator.
[BCDEFG] Any one of these characters, B C D E F G.
)
[#b] Any one of the characters, # b.
? Says the previous entity (# or b) is optional.
$mods Any one of the modifiers, e.g. maj m min ...
? Says the previous entity (maj m min ...) is optional.
)
| An "OR" operator.
( A capture group. (To encapsulate $regex_2.)
A(?=\s+[a-z]) An "A" that is followed by at least one whitespace
character, then a lower-case letter.
)
)
\s+ A bunch of whitespace.