C#正規表現で文字をReplaceする3つの方法と使い分け

目次

正規表現(Regular expression,Regex)について

正規表現は自分にとって不可欠な存在です。非常に頻繁に使います。
パターンの文法はいろいろあるものの、よく使ういくつかを覚えておけば、結構不便なく使えます。
先日はMatchされた文字列の置換(Replace)について、少し困った場面に出遭い勉強になりましたので、ここで整理しておきたいと思います。

Regex.Replace()メソッドの3つの使い方

まず例として以下のinput文字列とパターンがあるとします。

string input = "1月30万円、2月60万円、3月100万円"; //"30万円","60万円","100万円"をMatchするpattern string ptnAmount = @"(\d+)万円";

1. 一斉置換の結果だけがほしいときの使い方

これは一番シンプルです。一斉置換の結果だけほしくて、個々のMatchに興味がない場合:

//個々のMatchを追跡せずに一斉置換 string output = Regex.Replace(input, ptnAmount, "${1}0,000円"); Console.WriteLine("output:"); Console.WriteLine(output);

結果出力、ただ置換するだけですので、100万円を超えた場合の表示に瑕疵があります:

output: 1月300,000円、2月600,000円、3月1000,000円

2. 個々のMatch結果を見たり処理したいときの使い方

個々のMatch結果を見たり処理したいときに使う方法です:

//個々のMatchを追跡して置換の前後を表示する string output1 = Regex.Replace(input, ptnAmount, m => { string after = $"{int.Parse(m.Groups[1].Value) * 10000:#,###}円"; Console.WriteLine($"{m.Value} -> {after}"); return (after); }); Console.WriteLine("output1:"); Console.WriteLine(output1);

結果出力、個々のMatchの置換前後の比較が表示され、100万円以上の数字の表示はまともになりました:

30万円 -> 300,000円 60万円 -> 600,000円 100万円 -> 1,000,000円 output1: 1月300,000円、2月600,000円、3月1,000,000円

3. 上記2と同じでMatch.Result(replace)を使う方法

//上記同様、個々のMatchを追跡して置換の前後を表示する string output2 = Regex.Replace(input, ptnAmount, m => { //個々のMatchにReplaceを指定して置換する string after = m.Result($"{int.Parse(m.Groups[1].Value) * 10000:#,###}円"); Console.WriteLine($"{m.Value} -> {after}"); return (after); }); Console.WriteLine("output2:"); Console.WriteLine(output2);

結果出力も方法2と同じです。

30万円 -> 300,000円 60万円 -> 600,000円 100万円 -> 1,000,000円 output2: 1月300,000円、2月600,000円、3月1,000,000円

string Match.Result (string replacement)でも同じ結果を返しますが、使う意味はあるのでしょうか?

少し深堀:Match.Result()でなければならない?シナリオ

まずMatchのパターンを変える

//"万円"を含まない"30","60","100"をMatchするpattern string ptnNumberOnly = @"(\d+)(?=万円)";

そしてreplace文字列は開発者指定ではなくユーザー入力で取得する

//Replaceはユーザー入力から取得=開発時には分からない Console.WriteLine("Specify the replacement:"); string replace = Console.ReadLine();

この状況で個々のMatchを追跡しながら一斉置換する

//個々のMatchを追跡して置換の前後を表示する string output3 = Regex.Replace(input, ptnNumberOnly, m => { ////replaceはユーザー入力のため、内容が分からないので、 ////ここで開発者は処理しようがない。 ////以下のコードも動作しない、なぜならm.Valueに"万円"が消えているため ////ptnNumberOnlyはm.ValueにMatchしない。 //string after = Regex.Replace(m.Value, ptnNumberOnly, replace); ////以下は動作するコード ////m.Result(replace)はm.Valueではなく、 ////input全体でMatchして、さらに個々のReplace結果を返す。 string after = m.Result(replace); Console.WriteLine($"{m.Value} -> {after}"); return (after); }); Console.WriteLine("output3:"); Console.WriteLine(output3);

結果出力:

Specify the replacement: (${1}) ← ユーザー入力 30 -> (30) 60 -> (60) 100 -> (100) output3: 1月(30)万円、2月(60)万円、3月(100)万円

まとめ:Match.Result()が必要なシナリオ

  • 個々のMatch結果を追跡したい
    且つ
  • パターンは入力文字列全体にMatchするが、個々のMatch結果に通用しない
    且つ
  • replace文字列はユーザー指定等、内容が分からない

以上3つの条件がそろえばMatch.Result()が必須ではないかと思います。
結構厳しい条件のようですが、このまえあっさりはまりました(*^^)v
ドキュメントを読んでも調べて結果が出てこず、いろいろ試したら意外と簡単な方法がありました。
以上、備忘をかねての整理でした。

コメント

このブログの人気の投稿

C# WebView2.ExecuteScriptAsync()のいくつかの使い方とDebug方法

C# 外部ライブラリを使わずに半角→全角カタカナ変換

C# WebView2を通じてWebサーバーなしでJavaScriptからローカルファイルを読み書き