正規表現でそれを行うことは可能ですが、扱いにくくなるので、次のようにします。
data = <<EOT
group1
Members:
m/a
m/b
group2
Members:
m/c
m/d
m/e
group3
No Members
EOT
pp data.lines.slice_before(/^group/).to_a
=> [["group1\n", " Members: \n", " m/a\n", " m/b\n"],
["group2\n", " Members: \n", " m/c\n", " m/d\n", " m/e\n"],
["group3\n", " No Members\n"]]
質問の要件を満たすために残りをクリーンアップすると、次のようになります。
data.gsub(%r{\bm/}, '').split(/\n\s*/).reject{ |s| s[/\bMembers\b/] }.slice_before(/^group/).to_a
=> [["group1", "a", "b"], ["group2", "c", "d", "e"], ["group3"]]
構文解析の要点は本当ににありslice_before
ます。他のすべては、アレイとクリーンアップを作成しています。
それを分解する:
gsub(%r{\bm/}, '')
不要なものを取り除きm/
ます。
split(/\n\s*/)
行末の文字列を配列に分割すると同時に、先頭の空白を削除します。
reject{ |s| s[/\bMembers\b/] }
'Members'を別の単語として含む行を拒否します。
slice_before(/^group/)
文字列の先頭にある「group」で始まるチャンクに配列を分割します。
to_a
すべてを再び配列に変換します。