.NET C# 正規表現 文字列内から指定キーワードに挟まる文字列を抽出する関数

# やりたいこと
タイトル通りです。ある文字列内から特定のキーワードの間に挟まる文字列を抽出するだけです。
世の中に参考となる記事は本当に沢山あると思いますが、さくっと使える関数としてご紹介します。

今回紹介する処理は、文字列内からキーワードAとキーワードBの間に挟まる文字列の抽出です。
なので、文字列次第では、結果が複数ヒットする可能性があります。
結果を複数返す場合と、一つとして返す場合の二通りをご紹介します。

# 環境
Windows 10 Pro 64bit
Visual Studio 2022 Community
.NET 6

# 実装例　
## 複数の結果を配列として取得する関数

~~~C#:C#
       /// <summary>
        /// 文字列内から指定したキーワードの間に挟まる文字列の配列を取得します
        /// </summary>
        /// <param name="source">抽出対象の文字列</param>
        /// <param name="frontKeyword">条件となる前のキーワード</param>
        /// <param name="behindKeyword">条件となる後のキーワード</param>
        /// <returns></returns>
        private static string[] GetStringArrayBetweenKeywords(string source, string frontKeyword, string behindKeyword)
        {
            // 正規表現パターン
            var pattern = $"({frontKeyword})(?<group>.*?)({behindKeyword})";

            // マッチオプション
            var options =
                        // 大文字小文字無視
                        RegexOptions.IgnoreCase |
                        // 改行無視
                        RegexOptions.Singleline;

            //正規表現でマッチするか調べる
            if (Regex.IsMatch(source, pattern))
            {
                //正規表現でマッチした文字列の配列を返す
                return Regex.Matches(source, pattern, options).Select((x) => x.Groups["group"].Value).ToArray();
                
            }
            else//マッチしない場合
            {
                //空配列を返す。必要に応じてnull等に変えてください
                return Array.Empty<string>();
                //return null;
            }
        }
~~~
## 結果を一つの文字列(最長)として取得する関数
~~~C#:C#
        /// <summary>
        /// 文字列内から指定したキーワードの間に挟まる最長の文字列を取得します。
        /// </summary>
        /// <param name="source">抽出対象の文字列</param>
        /// <param name="frontKeyword">条件となる前のキーワード</param>
        /// <param name="behindKeyword">条件となる後のキーワード</param>
        /// <returns></returns>
        private static string GetStringBetweenKeywords(string source, string frontKeyword, string behindKeyword)
        {
            // 正規表現パターン
            var pattern = $"({frontKeyword})(?<group>.*)({behindKeyword})";

            // マッチオプション
            var options =
                        // 大文字小文字無視
                        RegexOptions.IgnoreCase |
                        // 改行無視
                        RegexOptions.Singleline;

            //正規表現でマッチするか調べる
            if (Regex.IsMatch(source, pattern))
            {
                //正規表現でマッチした文字列の配列を返す
                return Regex.Match(source, pattern, options).Groups["group"].Value;
            }
            else//マッチしない場合
            {
                //空文字を返す。必要に応じてnull等に変えてください
                return string.Empty;
                //return null;
            }
        }
~~~
## 実行結果の例

| 引数 | 値 |
|:-:|:-:|
| source  | 昨日の天気は雨。今日の天気は晴れ。  |
| frontKeyword  | 天気は  |
| behindKeyword  |  。 |
### 複数の結果の場合

雨
晴れ

### 単一(最長)の場合
雨。今日の天気は晴れ

## 解説(少しだけ)
正規表現を解説するとなると大変なのでポイントだけ。
これは、正規表現のグループ化を用いた手法で、尚且つ最短マッチと、最長マッチを使い分けた例です。
複数結果の方が、最短マッチで　 __.*?__　の部分でがその指定となっています。
単一結果の方は 　__.*__　としています。
たしか、.NETは標準で最長マッチする仕様だったような。

「最短とか、最長とか言われてもよくわからん」という人はこの実行結果を見るとイメージしやすいのではないでしょうか。

## あとがき
正規表現があるお陰で、文字列操作はとても楽な時代になりました。昔は本当に大変でした。
やりたい事の数=関数の数 ってな感じだったのでどれだけ作った事か。。。
そんな事を思う私も、若いつもりが十分年寄りになってきたんだと最近しみじみ思うようになりました。

そんな事を思いつつ、とても便利な正規表現を、結局関数実装として紹介している点が一番のポイントです。
参考？になれば幸いです。

# 本当に参考となる、参考とした記事
https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/regular-expressions

https://dobon.net/vb/dotnet/string/regex.html