実は私、結構文字列操作をする機会が多いんですよね。例えば手元のCSVファイルからデータベース更新用のInsert文やUpdate文を作成したり、サンプルソースをブログに貼る際に行の先頭にある空白を削除するとか、ある特定の文字列以降を削除したいとか・・・
C#には便利な文字列操作の関数が用意されていますが、引数に適切な値を指定しないとエラーになるため、色々と考慮する必要があり結構面倒です。
ということで、今回は既存の文字列操作を組み合わせることで、エラーに強く、かつ痒いところに手が届く文字列操作の実用例を、サンプルソース付きで紹介したいと思います。
関数化しているので、そのままコピペでお使いいただけます。興味のある方は、是非この記事をご一読ください。
C#で文字列を操作するためのクラス
C#で文字列を扱う場合、Stringクラスと StringBuilder クラスの2種類が用意されています。
Stringクラスは、文字列型のデータを扱うときに登場する string 型のことです。
stirng str = “文字列操作するよ”;
C#の言語仕様上、String を string と記述できるだけの話で、両者は同じものです。なぜ2つ用意されているかは大人の事情が絡んでくるのかもしれませんが、int や double のようなC言語の流れを汲んで string でも記述できるようにしたのではないかと思います。
StringBuilderクラス は、高速に文字列操作を行うことに特化したクラスです。string型は変数に代入される度に新たなメモリ領域が確保されるのに対し、StringBuilderは既に確保済みのメモリ領域に追加していきます。

一般的には string クラスを使いますが、数千~数万回のループ処理の中で文字列操作を行う場合で、処理速度が問題になる場合は StringBuilder が推奨されます。
本記事では最も馴染みのある string クラスを使った文字列操作について紹介しています。
文字列操作の基本メソッド
以下がC#の標準で備わっている文字列操作の一覧です。
加工内容 | 実例 | 結果 |
---|---|---|
文字列の結合 | ◆文字列配列をカンマ区切りで結合 string[] array = new str[]{“AB”,”CD”,”EF”}; string.Join(“,”,array ); | “AB,CD,EF” |
文字列の分割 | ◆文字列をカンマで区切って配列に格納 string str = “AB,CD,EF”; str.Split(‘,’); ◆区切り文字を複数指定する場合 string str = “AB#CD/EF”; str.Split(new char[]{‘/’,’#’}); | {“AB”,”CD”,”EF”} {“AB”,”CD”,”EF”} |
前後の文字列削除 | ◆文字列の前後空白を削除 string str = ” ABCDEF “; str.Trim(); ◆先頭の空白を削除する場合 str.TrimStart(); ◆末尾の空白を削除する場合 str.TrimEnd(); ◆複数の文字を削除したい場合 string str = ” * ABCDEF ** *”; str.TrimEnd(new char[]{‘*’,’ ‘}) | “ABCDEF” “ABCDE “ ” ABCDE” “ABCDE” |
指定範囲の列取り出し | ◆0から始まる指定位置以降を取り出す string str = “ABCDE12345”; str.Substring(5); ◆指定範囲を取り出す場合 (下記は5文字目から3文字分取り出す) str.Substring(5,3); | “12345” “123” |
文字列の置き換え | ◆指定した文字列を置換する string str = “ABCDE12345”; str.Replace(“ABC”,”@”); ◆文字列を削除する場合は空文字を指定 str.Replace(“ABC”,””); | “@DE12345” “CDE12345” |
文字列のフォーマット | ◆文字列の前後に任意の文字列を付加する string str = “12345”; string format = “##**{0}**##”; string.Format(format,str); ※詳細は「dobon.net」さんのサイトをご覧下さい | “##**12345**##” |
前後の空白埋め | ◆右又は左に空白を埋めて、指定した桁数に揃える。 string str = “ABCDE” str.PadLeft(10); str.PadRight(10); ◆第2引数に埋めたい文字を指定することも可能 str.PadLeft(10,’*’); str.PadRight(10,’0′); | ” ABCDE” “ABCDE “ “*****ABCDE” “ABCDE00000” |
文字列操作の応用
ここからは、基本メソッドを使った応用例です。文字列の長さをチェックし、引数に範囲外の値が指定されてもエラーにならない(例外が発生しない)ようにしています。
また、今回のメソッドは拡張メソッドとして作成しています。拡張メソッドについては「【C#】これで完璧!拡張 メソッドの作り方と使い方」に詳しく記載していますが、C#のTrimやSubstringと同様にオブジェクトに対して ドット+メソッド名(例: “ABC”.Substring(5))で呼び出す方法です。
普通の関数として利用する場合は、第一引数の this キーワードを全て削除して下さい。
文字列の先頭/末尾から指定文字数を取り出す(Left/Right/Mid)
文字列の先頭、又は末尾から指定文字数分を取得します。Midの第一引数に指定する開始位置は、1から数える点にご注意ください。
使用例 | 実行結果 |
---|---|
“ABCDE12345”.Left(3) | “ABC” |
“ABCDE12345”.Right(3) | “345” |
“ABCDE12345”.Mid(3,4) | “CDE1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/// <summary> /// 先頭から指定した文字数を取り出す。 /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="n">取り出したい文字数</param> /// <returns></returns> public static string Left(this string self, int n) { if (self == null || self == "") return ""; return self.Substring(0, (self.Length < n) ? self.Length : n); } /// <summary> /// 末尾から指定した文字数を取り出す。 /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="n">取り出したい文字数</param> /// <returns></returns> public static string Right(this string self, int n) { if (self == null || self == "") return ""; int pos = self.Length - n; return self.Substring((pos < 0) ? 0 : pos); } /// <summary> /// 先頭の指定文字目から指定文字数分を取り出す。 /// 先頭は1文字目から開始する(Visual Basic の Midと互換)。 /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="n">取り出したい位置(0~)</param> /// <param name="length">取り出したい文字数</param> /// <returns></returns> public static string Mid(this string self, int n, int length) { if (self == null || self == "") return ""; int pos = n - 1; int size = self.Length - pos - length; return self.Substring((pos < 0) ? 0 : pos, (size < 0) ? self.Length - pos : length); } |
文字列の先頭/末尾から指定文字数をカットする(CutStart,CutEnd,Cut)
文字列の先頭、又は末尾から指定文字数分をカットします。Cutの内部では、CutStartとCutEndを使っています。
使用例 | 実行結果 |
---|---|
“ABCDE12345”.CutStart(3) | “DE12345” |
“ABCDE12345”.CutEnd(3) | “ABCDE12” |
“ABCDE12345”.Cut(3,2) | “DE123” |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/// <summary> /// 先頭から指定文字数分だけカットする。 /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="n">カットしたい文字数</param> /// <returns></returns> public static string CutStart(this string self, int length) { if (self == null || self == "" || (length >= self.Length)) return ""; if (length < 0) return self; return self.Substring(length); } /// <summary> /// 末尾から指定文字数分だけカットする。 /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="length">カットしたい文字数</param> /// <returns></returns> public static string CutEnd(this string self, int length) { if (self == null || self == "") return ""; length = self.Length - length; if (length < 0) return ""; return self.Substring(0, length); } /// <summary> /// 指定した文字数分だけ先頭、末尾からカットする。 /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="start_len">先頭からカットしたい文字数</param> /// <param name="end_len">末尾からカットしたい文字数</param> /// <returns></returns> public static string Cut(this string self, int start_len, int end_len) { return CutEnd(CutStart(self, start_len), end_len); } |
指定文字列を起点に、それ以前/それ以降を取得する(Until,After,Between)
Untilは指定した文字が見つかった位置までの文字列を返し、Afterは指定した文字列が見つかった位置以降の文字列を返します。
Until、After共に第2引数に true を指定すると、指定した文字列を含んだ結果を返します。
Between は、開始文字列と終了文字列の間を取り出します。
使用例 | 実行結果 |
---|---|
“ABCDE12345”.Until(“CDE”) “ABCDE12345”.Until(“CDE”,true) | “AB” “ABCDE” |
“ABCDE12345”.After(“CDE”) “ABCDE12345”.After(“CDE”,true) | “12345” “CDE12345” |
“ABCDE12345”.Between(“DE”,”34″) | “12” |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
/// <summary> /// 指定した文字列が見つかるまでの文字列を取得する /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="str">指定文字列</param> /// <param name="isInclude">取り出した結果に指定文字列を true:含む/false:含まない</param> /// <returns></returns> public static string Until(this string self, string str, bool isInclude = false) { int pos = self.IndexOf(str); pos += (isInclude) ? str.Length : 0; return (pos < 0) ? self : self.Substring(0, pos); } /// <summary> /// 指定した文字列が見つかった以降の文字列を取得する /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="str">指定文字列</param> /// <param name="isInclude">取り出した結果に指定文字列を true:含む/false:含まない</param> /// <returns></returns> public static string After(this string self, string str, bool isInclude = false) { int pos = self.IndexOf(str); pos += (isInclude) ? 0 : str.Length; return (pos < 0) ? self : self.Substring(pos).TrimStart(); } /// <summary> /// 指定した文字列から始まり、指定した文字列で終わる範囲を取り出す /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="startString">指定文字列(開始)</param> /// <param name="endString">指定文字列(終了)</param> /// <returns></returns> public static string Between(this string self, string startString, string endString) { var start = self.IndexOf(startString); if (start < 0) return ""; start += startString.Length; var end = self.IndexOf(endString, start); if (end < 0) return self.Substring(start); return self.Substring(start, end - start); } |
文字列をシフト/ローテートする(Shft,Rotate)
文字列をシフト又はローテートします。

Shiftの第2メソッドに true を指定すると、押し出された分だけ半角スペースを補充します。
使用例 | 実行結果 |
---|---|
“ABCDE12345”.Shift(2) “ABCDE12345”.Shift(2,true) “ABCDE12345”.Shift(-2) “ABCDE12345”.Shift(-2,true) | “ABCDE123” ” ABCDE123″ “CDE12345” “CDE12345 “ |
“ABCDE12345”.Rotate(2) “ABCDE12345”.Rotate(-2) | “CDE12345AB” “45ABCDE123” |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/// <summary> /// cnt がプラスなら右へ、マイナスなら左へ文字列をシフトする /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="cnt">シフトしたい文字数</param> /// <returns></returns> public static string Shift(this string self, int cnt,bool isFill = false) { int len = self.Length; string res = ""; if (self == "" || cnt == 0 || len < Math.Abs(cnt)) { return (isFill) ? res.PadRight(len) : ""; } if (cnt < 0) { res = self.Substring(-1 * cnt); } else { res = self.Substring(0, self.Length - cnt); } if (isFill) { return (cnt < 0) ? res.PadRight(len) : res.PadLeft(len); } else { return res; } } /// <summary> /// cnt がプラスなら右へ、マイナスなら左へ文字列をローテートする /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="cnt">ローテートしたい文字数</param> /// <returns></returns> public static string Rotate(this string self, int cnt) { if (self == "" || cnt == 0 || self.Length < Math.Abs(cnt)) { return self; } if (cnt < 0) { cnt *= -1; return self.Substring(cnt, self.Length - cnt) + self.Substring(0, cnt); } else { return self.Substring(self.Length - cnt) + self.Substring(0, self.Length - cnt); } } |
文字列を連続置換する(MultiReplace)
変換前、変換後の対をなすタプル配列を使って、一気に文字列置換します。このメソッドは速度を優先するため、StringBuilderを使っています。
var rep = new (string,string)[]{(“AB”,”ab”),(“AB12″,”@@@@”),(“45″,”XY”)};
使用例 | 実行結果 |
---|---|
“ABCDEAB12345”.MultiReplace(rep) | “abCDE@@@@3XY” |
タプル配列で文字列置換する場合、置換順序によって意図しない結果になる可能性があります。例えば今回の例では、”AB”を”ab”に、”AB12”を”@@@@”に変換するように指定していますが、先に”AB”が置き換わってしまうと、”AB12”が存在しなくなり、”@@@@”に置き換えることが出来ません。
この対策として、 OrderByDescending メソッドを使って変換前文字列の長さでソートしてから、連続置換するようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/// <summary> /// 文字列の連続置換 /// </summary> /// <param name="self">操作対象文字列</param> /// <param name="array">置換したい文字列(タプル形式の配列で指定)</param> /// <returns></returns> public static string MultiReplace(this string self, (string before, string after)[] array) { //タプル配列を文字列の長さでソートする var sorted = array.OrderByDescending(i => i.before.Length); //連続置換を実行する var sb = new StringBuilder(self); foreach (var item in sorted) { sb.Replace(item.before, item.after); } return sb.ToString(); } |
まとめ
今回はC#において標準で使える文字列操作メソッドのおさらいと、それらを利用した応用メソッドについて紹介しました。
標準で使えるメソッドは、例えば5文字の文字列に対して7文字目以降を取得するような場合、容易にエラーが発生してしまいます。
これは、ユーザーが画面から入力したり、可変長のCSVデータを取り扱う場合など、処理したい文字列の長さが不定な場合、様々な考慮が必要になるということです。
今回は、その様な考慮をしつつ、標準で用意されていない操作を拡張メソッドとして紹介しました。
そのままコピペして使っていただけますので、必要に応じてご利用いただければ幸いです。