C#でプログラミングを行う際、文字列の操作は避けて通れない非常に重要な要素です。
特に、CSV形式のデータ処理やユーザー入力の解析、ログファイルの読み込みなど、特定の区切り文字に基づいて文字列を切り分ける「文字列分割」の技術は、実務レベルで頻繁に利用されます。
C#には、これを実現するための強力なSplitメソッドが用意されていますが、単純な分割だけでなく、複数の区切り文字への対応や、空白要素の除去といった高度なオプション設定を知ることで、より美しく効率的なコードを記述できるようになります。
本記事では、初心者から中級者まで役立つ、C#における文字列分割のテクニックを網羅的に詳しく解説していきます。
C#における文字列分割の基本
C#のstring.Splitメソッドは、文字列を指定した境界で分割し、その結果を文字列の配列として返すメソッドです。
最もシンプルな形では、一つの文字(char)を区切りとして指定します。

Splitメソッドの基本的な役割
Splitメソッドは、「どこで切るか」という情報を引数に渡すことで、元の文字列を断片化します。
最もよく使われるのは、カンマ(,)やタブ、スペースなどで区切られたデータを処理する場面です。
分割後の各データはstring[](文字列配列)に格納されるため、その後のループ処理やインデックスによるアクセスが容易になります。
単一文字による分割のサンプルコード
まずは、最も基本的なカンマ区切りの分割例を見てみましょう。
using System;
class Program
{
static void Main()
{
// 分割対象の文字列
string csvData = "C#,Java,Python,Ruby";
// カンマ(',')で分割
string[] languages = csvData.Split(',');
// 結果の出力
foreach (string lang in languages)
{
Console.WriteLine($"言語: {lang}");
}
}
}
言語: C#
言語: Java
言語: Python
言語: Ruby
この例では、csvData.Split(',')によって、カンマが見つかるたびに新しい要素として切り出されています。
非常にシンプルですが、これがすべての分割処理の土台となります。
複数の区切り文字を指定する方法
実際の開発では、区切り文字が一つとは限りません。
例えば、「カンマとセミコロンの両方が混在している」といった状況や、「スペースとスラッシュのどちらでも分割したい」といったケースがあります。

配列を使用した複数文字の指定
Splitメソッドの引数には、文字の配列(char[])を渡すことができます。
これにより、「指定した文字のいずれかが見つかった場所」で分割を行うことが可能になります。
複数文字分割のコード例
以下のコードでは、日付と時刻の区切りが混在している文字列を、一括で分割しています。
using System;
class Program
{
static void Main()
{
// 複数の区切り文字が混在する文字列
string dateTimeStr = "2026/01/16 12:30:45";
// 分割に使用する文字の配列を作成
char[] delimiters = { '/', ' ', ':' };
// 配列を引数に渡して分割
string[] parts = dateTimeStr.Split(delimiters);
// 結果を表示
for (int i = 0; i < parts.Length; i++)
{
Console.WriteLine($"Index[{i}]: {parts[i]}");
}
}
}
Index[0]: 2026
Index[1]: 01
Index[2]: 16
Index[3]: 12
Index[4]: 30
Index[5]: 45
このように、複数の記号が混じっていても、一つのSplit呼び出しで綺麗に分解できます。
これは、複雑なフォーマットのテキストファイルを解析する際に非常に便利です。
文字列(String)を区切り文字として使う
これまでの例は「一文字」での分割でしたが、「特定の文字列(複数文字の並び)」を区切りにしたい場合もあります。
例えば、"<BR>"というタグや、" -- "といった特定の記号の組み合わせを区切りにするケースです。

string配列による分割
文字列で分割を行う場合は、引数にstring[]を渡します。
ただし、単一文字の場合とは異なり、StringSplitOptionsという列挙型の引数も一緒に指定する必要があります。
using System;
class Program
{
static void Main()
{
string text = "Apple[AND]Orange[AND]Banana";
// 区切りたい「文字列」を配列で定義
string[] separators = { "[AND]" };
// 文字列配列とオプションを指定して分割
string[] fruits = text.Split(separators, StringSplitOptions.None);
foreach (var fruit in fruits)
{
Console.WriteLine($"果物: {fruit}");
}
}
}
果物: Apple
果物: Orange
果物: Banana
StringSplitOptions.Noneは、特別な処理を行わない(デフォルトの状態)ことを意味します。
この指定により、単一文字だけでなく「文字列の並び」を基準にした柔軟な分割が可能になります。
空白要素の削除とオプション設定
文字列を分割すると、区切り文字が連続している場合に空の文字列(Empty String)が結果に含まれてしまうことがあります。
これをどう制御するかが、実務におけるSplit活用の鍵となります。

StringSplitOptions.RemoveEmptyEntriesの活用
例えば、"A,,B"という文字列をカンマで分割すると、通常は3つの要素が返ります。
しかし、多くの場合は真ん中の空要素は不要です。
そのような時にStringSplitOptions.RemoveEmptyEntriesを使用します。
using System;
class Program
{
static void Main()
{
string rawData = "C#,,Java,,,Python";
// オプションなし(デフォルト)
string[] defaultSplit = rawData.Split(',');
Console.WriteLine($"--- デフォルト (要素数: {defaultSplit.Length}) ---");
foreach (var s in defaultSplit) Console.WriteLine($"'{s}'");
// 空要素を削除するオプションを指定
string[] cleanSplit = rawData.Split(',', StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine($"\n--- オプション適用後 (要素数: {cleanSplit.Length}) ---");
foreach (var s in cleanSplit) Console.WriteLine($"'{s}'");
}
}
--- デフォルト (要素数: 6) ---
'C#'
''
'Java'
''
''
'Python'
--- オプション適用後 (要素数: 3) ---
'C#'
'Java'
'Python'
前後の空白をトリミングする(TrimEntries)
.NET 5以降では、さらに便利なStringSplitOptions.TrimEntriesが追加されました。
これは、分割された各要素の前後にある余分なスペースを自動的に削除してくれる機能です。
using System;
class Program
{
static void Main()
{
string data = " Apple , Orange , Banana ";
// 分割と同時にトリミングを行い、かつ空要素も消す
string[] results = data.Split(',',
StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
foreach (var item in results)
{
Console.WriteLine($"結果: '{item}'");
}
}
}
結果: 'Apple'
結果: 'Orange'
結果: 'Banana'
このように、論理和演算子(|)を使って複数のオプションを組み合わせることで、非常にクリーンなデータを一行で取得できます。
分割数の制限(最大分割数)
すべての箇所で分割するのではなく、「最初の2つだけ分割して、残りは一つの文字列として保持したい」というケースがあります。
これはログの解析などで、先頭の時刻とレベルだけを取り出し、メッセージ本文はそのまま残したい時などに役立ちます。

count引数による制限
Splitメソッドのオーバーロードには、整数型のcountを受け取るものがあります。
これに分割後の最大要素数を指定します。
using System;
class Program
{
static void Main()
{
string info = "2026-01-16-LOG-Error-Occurred-At-System";
// 最大3つの要素に分割する
string[] parts = info.Split('-', 3);
for (int i = 0; i < parts.Length; i++)
{
Console.WriteLine($"Part {i}: {parts[i]}");
}
}
}
Part 0: 2026
Part 1: 01
Part 2: 16-LOG-Error-Occurred-At-System
3番目の要素に、残りのすべての文字列が含まれていることがわかります。
これにより、不必要に細かく分割されるのを防ぎ、パフォーマンスの向上やロジックの簡略化に繋がります。
特殊な分割テクニック:正規表現の利用
単純な文字や文字列だけでは対応できない複雑な条件(例:数字が出てきたところで切りたい、大文字小文字を区別せず特定の単語で切りたいなど)がある場合、System.Text.RegularExpressions.Regex.Splitを利用します。

Regex.Splitによる高度な分割
正規表現を使えば、パターンに基づいた分割が可能になります。
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string input = "Step1:Open,Step2:Read;Step3:Close";
// 記号(: か , か ;)のいずれかで分割する正規表現
string pattern = "[:|;|,]";
string[] results = Regex.Split(input, pattern);
foreach (var res in results)
{
Console.WriteLine($"要素: {res}");
}
}
}
要素: Step1
要素: Open
要素: Step2
要素: Read
要素: Step3
要素: Close
Regex.Splitは非常に強力ですが、通常のstring.Splitに比べると処理コストが高いため、「どうしても単純な分割では解決できない場合」に限定して使用するのがベストプラクティスです。
パフォーマンスと注意点
大量のデータを処理するアプリケーションにおいて、文字列の分割はメモリ消費の要因になり得ます。
特にループ内で頻繁にSplitを呼び出すと、大量のstring[]と新しいstringオブジェクトが生成され、ガベージコレクション(GC)の負荷が高まります。
分割時のメモリ管理
Splitメソッドを呼び出すたびに、新しい配列と新しい文字列インスタンスがヒープメモリ上に確保されます。
もし、分割後の文字列を単に読み取るだけで、新しい文字列として保持する必要がない場合は、現代的なC#の機能であるReadOnlySpan<char>の検討も有効です。
| 手法 | メモリ消費 | 柔軟性 | 推奨シーン |
|---|---|---|---|
| string.Split | 高め | 高い | 一般的な開発、小~中規模データ |
| Regex.Split | 高い | 非常に高い | 複雑なパターン解析 |
| Span<char> | 極めて低い | 低め | 高パフォーマンスが要求される通信や解析 |
実装時のコツ
- 不必要な分割を避ける
本当にすべての要素が必要か検討し、
count引数で制限する。- オプションを正しく使う
後から
Trim()をループで回すくらいなら、最初からTrimEntriesを指定する方が効率的。- 静的な解析
もし区切り文字が固定なら、
char[]のインスタンスを事前に作成(static readonlyなど)しておき、使い回すことで微細な最適化が可能。
まとめ
C#のSplitメソッドは、単純な文字列の切り分けから、複雑なオプションを組み合わせたデータのクレンジングまで、非常に幅広い用途に対応しています。
単一文字での分割といった基本を理解した上で、複数文字への対応や空要素の削除、そして最大分割数の制限といった応用テクニックを使い分けることが、美しく保守性の高いコードを書くための第一歩となります。
特に.NET 5以降で利用可能になったTrimEntriesなどの新しいオプションは、これまで手動で行っていた面倒な処理を劇的にシンプルにしてくれます。
プログラムの要件に合わせて最適な分割手法を選択し、効率的な文字列操作を実現しましょう。
今回の内容をマスターすれば、CSV解析やログ処理といった日常的なコーディング作業がよりスムーズに進むはずです。
