正規表現が出力を与える方法
se,dc(fr(lo)),km(ji)(hn),...
文字列からaz(se)(dc(fr(lo)))(km(ji)(hn))...
学習目的のみであるため、外部パッケージ/ライブラリを使用せずに上記のような結果を達成できるように、括弧間のテキストを取得するための正規表現の書き方を教えてください。
これは、再帰的な正規表現の典型的な例です:
\(((?:[^()]++|\((?1)\))*+)\)
正規表現を分解してみましょう:
\( # Literal (
( # Start of capturing group 1
(?: # Start of non-capturing group
[^()]++ # Match characters other than ()
| # OR
\((?1)\) # Recursively match bracketed () content
)*+ # End of non-capturing group, and repeat the whole group zero or more times.
) # End of capturing group 1
\) # Literal )
最初と最後にある2 つのリテラル ブラケット()
は、ブラケット内のテキストと一致するようにするためのものです。それらがなければ、代わりにバランスの取れた括弧でテキストの部分を一致させます。
この(?:[^()]++|\((?1)\))*+
部分では、1 組の括弧内にパターンが記述されています。
()
文字のシーケンスが存在する可能性があります(...)
または、 で始まり、 (サブルーチン呼び出しの効果により(
) が続き、で終わる括弧で囲まれた部分。(?:[^()]++|\((?1)\))*+
(?1)
)
(...)
また、互いにインターリーブされた非ブラケット シーケンスとブラケット部分の 0 または多数のインスタンスが存在する可能性があります。
はサブルーチン呼び出し(?1)
と呼ばれ、グループをキャプチャすることで区切られたサブパターンと一致させることができます。この場合、はキャプチャ グループ 1 内にあるため、再帰的な効果が生じます。(?1)
my $str = "az(se)(dc(fr(lo)))(km(ji)(hn))(()aaa(()())(ff(dd)aa))";
my @arr = $str =~ /\(((?:[^()]++|\((?1)\))*+)\)/g;
print join("\n", @arr)
出力
せ dc(fr(lo)) km(ji)(hn) ()aaa(()())(ff(dd)aa)