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
ドキュメントを読んでも調べて結果が出てこず、いろいろ試したら意外と簡単な方法がありました。
以上、備忘をかねての整理でした。
コメント
コメントを投稿
個人情報を記入しないようご注意ください