C#のSplitで文字列を分割する方法|区切り文字・複数条件・空要素の扱いをわかりやすく解説

はじめに

C#で文字列を区切り文字ごとに分割したい場合は、主にString.Splitメソッドを使用します。カンマ区切りのデータ、スペースで区切られた単語、改行を含む文章、キーと値のペアなど、さまざまな文字列を簡単に分割できます。

C#
string text = "apple,orange,banana";
string[] fruits = text.Split(',');

このコードを実行すると、fruitsには次の3つの文字列が格納されます。

apple
orange
banana

Splitでは、1文字の区切り文字だけでなく、複数の区切り文字や::のような複数文字の区切り文字も指定できます。また、空要素の除外、前後の空白の削除、分割数の制限にも対応しています。String.Splitは、指定した文字または文字列を境界として、元の文字列から部分文字列の配列を作成するメソッドです。Microsoft Learn+1

この記事では、C#のSplitを使って文字列を分割する基本から、複数条件、空要素、正規表現、パフォーマンス上の注意点まで、サンプルコードを交えて解説します。

1. C#のSplitとは?文字列を分割する基本

1-1. String.Splitメソッドでできること

String.Splitメソッドは、文字列を指定した区切り位置で分割し、分割結果をstring[]として返します。

代表的な用途は次のとおりです。

  • カンマ区切りの文字列を分割する

  • スペースごとに単語を取り出す

  • 改行ごとに文章を分割する

  • 複数種類の記号を区切り文字として使用する

  • 空の要素を除外する

  • 分割数の上限を指定する

たとえば、商品名をパイプ記号で区切った文字列は、次のように分割できます。

C#
string text = "パソコン|マウス|キーボード";
string[] items = text.Split('|');

foreach (string item in items)
{
Console.WriteLine(item);
}

実行結果は次のとおりです。

パソコン
マウス
キーボード

1-2. Splitメソッドの基本構文と戻り値

基本的な構文は次のとおりです。

C#
string[] 結果 = 対象文字列.Split(区切り文字);

具体例を見てみましょう。

C#
string text = "red,green,blue";
string[] colors = text.Split(',');

Splitの戻り値はstring[]です。そのため、インデックスを指定して各要素を取得できます。

C#
Console.WriteLine(colors[0]); // red
Console.WriteLine(colors[1]); // green
Console.WriteLine(colors[2]); // blue

配列の要素数はLengthプロパティで取得できます。

C#
Console.WriteLine(colors.Length); // 3

1-3. 文字列を1つの区切り文字で分割する方法

1文字の区切り文字を指定する場合は、シングルクォートで囲んだcharを渡します。

C#
string text = "A-B-C";
string[] values = text.Split('-');

foreach (string value in values)
{
Console.WriteLine(value);
}

実行結果は次のとおりです。

A
B
C

'-'char型です。一方、"-"string型です。1文字だけを区切り文字にする場合は、通常はcharを使うと意図が明確になります。

1-4. 分割した文字列をforeachで順番に処理する方法

Splitの結果は配列なので、foreachを使って先頭から順番に処理できます。

C#
string text = "東京,大阪,名古屋";
string[] cities = text.Split(',');

foreach (string city in cities)
{
Console.WriteLine($"都市名: {city}");
}

実行結果は次のとおりです。

都市名: 東京
都市名: 大阪
都市名: 名古屋

要素番号も必要な場合は、for文を使用します。

C#
for (int i = 0; i < cities.Length; i++)
{
Console.WriteLine($"{i}: {cities[i]}");
}

2. 区切り文字を指定して文字列を分割する方法

2-1. カンマ区切りの文字列を分割する

カンマ区切りの文字列は、,を指定して分割します。

C#
string text = "100,200,300";
string[] values = text.Split(',');

foreach (string value in values)
{
Console.WriteLine(value);
}

実行結果は次のとおりです。

100
200
300

カンマの後ろに空白があるデータでは、分割後の文字列にも空白が残ります。

C#
string text = "apple, orange, banana";
string[] fruits = text.Split(',');

Console.WriteLine($"[{fruits[1]}]"); // [ orange]

空白も取り除きたい場合は、後述するStringSplitOptions.TrimEntriesを使用します。

2-2. スペース区切りの文字列を分割する

半角スペースで分割する場合は、' 'を指定します。

C#
string text = "C# Split String";
string[] words = text.Split(' ');

foreach (string word in words)
{
Console.WriteLine(word);
}

実行結果は次のとおりです。

C#
Split
String

スペースが連続していると、空の要素が発生します。

C#
string text = "C#  Split   String";
string[] words = text.Split(' ');

foreach (string word in words)
{
Console.WriteLine($"[{word}]");
}

空要素を除外するには、次のようにRemoveEmptyEntriesを指定します。

C#
string[] words = text.Split(
' ',
StringSplitOptions.RemoveEmptyEntries
);

2-3. 改行コードで文字列を分割する

複数行の文字列を行ごとに分割する場合は、改行コードを区切り文字として指定します。

C#
string text = "1行目\n2行目\n3行目";
string[] lines = text.Split('\n');

foreach (string line in lines)
{
Console.WriteLine(line);
}

ただし、Windowsの改行コードは一般に\r\nです。\nだけで分割すると、各行の末尾に\rが残る場合があります。

複数の改行コードに対応するには、次のように文字列配列を指定します。

C#
string text = "1行目\r\n2行目\n3行目\r4行目";

string[] lines = text.Split(
new[] { "\r\n", "\n", "\r" },
StringSplitOptions.None
);

foreach (string line in lines)
{
Console.WriteLine($"[{line}]");
}

現在の実行環境で使用される改行文字はEnvironment.NewLineで取得できます。

C#
string[] lines = text.Split(
new[] { Environment.NewLine },
StringSplitOptions.None
);

ただし、外部ファイルや通信データには異なるOSの改行コードが含まれる可能性があります。その場合は、\r\n\n\rをまとめて指定する方法が安全です。

2-4. タブ文字で文字列を分割する

タブ文字は\tで表します。

C#
string text = "商品名\t価格\t在庫数";
string[] columns = text.Split('\t');

foreach (string column in columns)
{
Console.WriteLine(column);
}

実行結果は次のとおりです。

商品名
価格
在庫数

タブ区切りのデータを処理する場合、空の列を保持する必要があるか確認してください。

C#
string text = "商品A\t\t10";
string[] columns = text.Split('\t');

Console.WriteLine(columns.Length); // 3
Console.WriteLine(columns[1] == ""); // True

RemoveEmptyEntriesを指定すると空の列が削除され、列番号がずれる可能性があります。表形式のデータでは、空要素を残した方がよいケースがあります。

2-5. char配列を使って複数の区切り文字を指定する

,;|のいずれかで分割したい場合は、char[]を使用します。

C#
string text = "red,green;blue|yellow";
char[] separators = { ',', ';', '|' };

string[] colors = text.Split(
separators,
StringSplitOptions.RemoveEmptyEntries
);

foreach (string color in colors)
{
Console.WriteLine(color);
}

実行結果は次のとおりです。

red
green
blue
yellow

1文字の区切り条件を複数指定するときは、char[]が適しています。

3. 複数文字の区切り文字でSplitする方法

3-1. string配列で複数文字の区切り文字を指定する

::--のように、区切り文字が2文字以上の場合はstring[]を使用できます。

C#
string text = "東京::大阪--名古屋";
string[] separators = { "::", "--" };

string[] cities = text.Split(
separators,
StringSplitOptions.None
);

foreach (string city in cities)
{
Console.WriteLine(city);
}

実行結果は次のとおりです。

東京
大阪
名古屋

char[]では、各文字が個別の区切り文字として処理されます。::全体を1つの区切り文字として扱いたい場合は、string[]を使用してください。

3-2. 「,」や「;」など複数条件で文字列を分割する

,または;で分割するだけであれば、char[]を使うのが簡単です。

C#
string text = "A,B;C,D";
char[] separators = { ',', ';' };

string[] values = text.Split(
separators,
StringSplitOptions.RemoveEmptyEntries
);

文字列配列でも指定できます。

C#
string[] values = text.Split(
new[] { ",", ";" },
StringSplitOptions.RemoveEmptyEntries
);

区切り文字がすべて1文字ならchar[]、複数文字を含むならstring[]を選ぶと分かりやすくなります。

3-3. 「::」や「--」を区切り文字として分割する

複数文字の区切り文字を1種類だけ指定する場合も、互換性を意識するなら配列形式で記述できます。

C#
string text = "name::Taro";
string[] parts = text.Split(
new[] { "::" },
StringSplitOptions.None
);

Console.WriteLine(parts[0]); // name
Console.WriteLine(parts[1]); // Taro

複数種類を指定する場合は、次のように配列へ追加します。

C#
string text = "A::B--C";
string[] parts = text.Split(
new[] { "::", "--" },
StringSplitOptions.RemoveEmptyEntries
);

3-4. 区切り文字そのものを文字列として扱う際の注意点

charstringは異なる型です。

C#
char charSeparator = ':';
string stringSeparator = "::";

char[]':'を指定すると、コロン1文字ごとに分割されます。

C#
string text = "A::B";
string[] parts = text.Split(':');

foreach (string part in parts)
{
Console.WriteLine($"[{part}]");
}

実行結果は次のとおりです。

[A]
[]
[B]

::全体で分割したい場合は、文字列として指定します。

C#
string[] parts = text.Split(
new[] { "::" },
StringSplitOptions.None
);

また、区切り文字は分割結果に含まれません。区切り文字自体も残したい場合は、後述するRegex.Splitや独自処理を検討します。

4. 空文字・空要素を除外して分割する方法

4-1. Splitで空の要素が発生する原因

区切り文字が連続している場合、区切り文字の間には長さ0の文字列があると判断されます。

C#
string text = "A,,B";
string[] values = text.Split(',');

foreach (string value in values)
{
Console.WriteLine($"[{value}]");
}

実行結果は次のとおりです。

[A]
[]
[B]

文字列の先頭や末尾に区切り文字がある場合も、空要素が発生します。

C#
string text = ",A,B,";
string[] values = text.Split(',');

結果は次のようになります。

""
"A"
"B"
""

隣接する区切り文字は、デフォルトでは空文字列の要素を生成します。Microsoft Learn

4-2. StringSplitOptions.RemoveEmptyEntriesで空要素を削除する

空要素を除外するには、StringSplitOptions.RemoveEmptyEntriesを指定します。

C#
string text = ",A,,B,";

string[] values = text.Split(
',',
StringSplitOptions.RemoveEmptyEntries
);

foreach (string value in values)
{
Console.WriteLine($"[{value}]");
}

実行結果は次のとおりです。

[A]
[B]

ただし、空要素に意味があるデータでは削除しないようにしてください。たとえば、次の文字列が「名前、メールアドレス、年齢」を表す場合、中央の空要素はメールアドレスが未入力であることを示します。

C#
string text = "山田太郎,,30";

RemoveEmptyEntriesを指定すると、30が2番目の要素に移動してしまいます。

4-3. StringSplitOptions.TrimEntriesで前後の空白を除去する

.NET 5以降では、StringSplitOptions.TrimEntriesを使って、分割した各要素の前後にある空白文字を削除できます。

C#
string text = " apple , orange , banana ";

string[] fruits = text.Split(
',',
StringSplitOptions.TrimEntries
);

foreach (string fruit in fruits)
{
Console.WriteLine($"[{fruit}]");
}

実行結果は次のとおりです。

[apple]
[orange]
[banana]

TrimEntriesは各要素の前後をトリミングしますが、要素内の空白は削除しません。

C#
string text = " John Smith , Tokyo ";

この場合、John Smithの単語間にあるスペースは維持されます。TrimEntries.NET 5以降で利用できます。Microsoft Learn

古い.NET環境では、LINQとTrimを組み合わせる方法があります。

C#
using System.Linq;

string[] fruits = text
.Split(',')
.Select(value => value.Trim())
.ToArray();

4-4. RemoveEmptyEntriesとTrimEntriesを組み合わせる

前後の空白を削除し、空要素も取り除きたい場合は、ビットOR演算子|でオプションを組み合わせます。

C#
string text = " apple, ,orange,, banana ";

StringSplitOptions options =
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries;

string[] fruits = text.Split(',', options);

foreach (string fruit in fruits)
{
Console.WriteLine($"[{fruit}]");
}

実行結果は次のとおりです。

[apple]
[orange]
[banana]

4-5. 空白だけの要素を除外するときの注意点

RemoveEmptyEntriesだけでは、空白だけで構成された文字列は除外されません。

C#
string text = "A,   ,B";

string[] values = text.Split(
',',
StringSplitOptions.RemoveEmptyEntries
);

Console.WriteLine(values.Length); // 3

中央の要素は空文字列ではなく、スペースを含む文字列だからです。

TrimEntriesと組み合わせると、空白だけの要素を空文字列にしてから除外できます。

C#
StringSplitOptions options =
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries;

string[] values = text.Split(',', options);

Console.WriteLine(values.Length); // 2

RemoveEmptyEntriesTrimEntriesを同時に指定すると、空白文字だけで構成された要素も結果から削除されます。Microsoft Learn+1

5. 分割する回数を指定する方法

5-1. count引数で分割数の上限を設定する

Splitcount引数を使うと、戻り値に含める要素数の上限を指定できます。

C#
string text = "A,B,C,D";

string[] values = text.Split(
new[] { ',' },
3,
StringSplitOptions.None
);

foreach (string value in values)
{
Console.WriteLine(value);
}

実行結果は次のとおりです。

A
B
C,D

countは区切り文字を処理する回数ではなく、返される部分文字列の最大数です。最後の要素には、分割されなかった残りの文字列が入ります。

5-2. 最初に見つかった区切り文字だけで分割する

最初の区切り文字だけで分けたい場合は、count2を指定します。

C#
string text = "key=value=extra";

string[] parts = text.Split(
new[] { '=' },
2,
StringSplitOptions.None
);

Console.WriteLine(parts[0]); // key
Console.WriteLine(parts[1]); // value=extra

設定文字列やHTTPヘッダーなど、最初の区切り文字より後ろをそのまま保持したい場合に便利です。

5-3. 文字列を2つの要素に分割する実装例

名前と値をコロンで分割する例です。

C#
string line = "Content-Type: application/json";

string[] parts = line.Split(
new[] { ':' },
2,
StringSplitOptions.TrimEntries
);

if (parts.Length == 2)
{
string name = parts[0];
string value = parts[1];

Console.WriteLine(name); // Content-Type
Console.WriteLine(value); // application/json
}

区切り文字が存在しない可能性を考慮し、parts.Lengthを確認してからアクセスすることが重要です。

5-4. count指定とStringSplitOptionsを併用する方法

countStringSplitOptionsは同時に指定できます。

C#
string text = " name = Taro = extra ";

string[] parts = text.Split(
new[] { '=' },
2,
StringSplitOptions.TrimEntries
);

Console.WriteLine(parts[0]); // name
Console.WriteLine(parts[1]); // Taro = extra

空要素の削除も必要な場合は、オプションを組み合わせます。

C#
StringSplitOptions options =
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries;

string[] parts = text.Split(
new[] { '=' },
2,
options
);

区切り文字が連続するデータでcountRemoveEmptyEntriesを併用すると、結果が直感と異なることがあります。複雑な入力については、実際のデータを使ったテストを用意してください。

6. Splitを使った実践的な文字列分割の例

6-1. CSV形式の文字列をカンマで分割する

引用符やエスケープを含まない単純なカンマ区切りデータであれば、Splitで処理できます。

C#
string line = "1001,ノートパソコン,98000";

string[] columns = line.Split(',');

string id = columns[0];
string productName = columns[1];
string price = columns[2];

Console.WriteLine($"ID: {id}");
Console.WriteLine($"商品名: {productName}");
Console.WriteLine($"価格: {price}");

列数を確認してから処理すると安全です。

C#
if (columns.Length != 3)
{
Console.WriteLine("列数が正しくありません。");
return;
}

ただし、次のように引用符で囲まれた値の中にカンマがあるCSVは、単純なSplit(',')では正しく処理できません。

1001,"東京,大阪",5000

この形式では、CSVの引用符やエスケープ規則に対応したパーサーを使用してください。

6-2. URLやファイルパスを区切り文字で分割する

URLのパス部分を分割する場合は、まずUriクラスでURLを解析します。

C#
var uri = new Uri(
"https://example.com/products/123/details?lang=ja"
);

string[] segments = uri.AbsolutePath.Split(
'/',
StringSplitOptions.RemoveEmptyEntries
);

foreach (string segment in segments)
{
Console.WriteLine(segment);
}

実行結果は次のとおりです。

products
123
details

URL全体を/で分割すると、スキームやホスト名まで混ざるため、先にUriで構造を解析する方が安全です。

ファイルパスを単純に分割する場合は、OSごとの区切り文字を考慮します。

C#
using System.IO;

string path = @"C:\work\data\sample.txt";

char[] separators =
{
Path.DirectorySeparatorChar,
Path.AltDirectorySeparatorChar
};

string[] parts = path.Split(
separators,
StringSplitOptions.RemoveEmptyEntries
);

ファイル名や拡張子を取得するだけなら、SplitよりもPathクラスが適しています。

C#
string fileName = Path.GetFileName(path);
string extension = Path.GetExtension(path);
string? directory = Path.GetDirectoryName(path);

6-3. 姓名や住所などスペースを含む文字列を分割する

姓名をスペースで分割する例です。

C#
string fullName = "山田 太郎";

string[] names = fullName.Split(
' ',
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries
);

if (names.Length >= 2)
{
Console.WriteLine($"姓: {names[0]}");
Console.WriteLine($"名: {names[1]}");
}

全角スペースが入力される可能性もある場合は、両方を指定します。

C#
string fullName = "山田 太郎";

char[] separators = { ' ', ' ' };

string[] names = fullName.Split(
separators,
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries
);

ただし、氏名や住所は必ずしも単純に2要素へ分けられるとは限りません。ミドルネーム、建物名、部屋番号などを考慮し、データ仕様を決めてから分割してください。

6-4. キーと値を「=」で分割してDictionaryに格納する

複数の設定値をセミコロンで分割し、それぞれを最初の=でキーと値に分ける例です。

C#
using System;
using System.Collections.Generic;

string text = "name=Taro;age=30;city=Tokyo";

var settings = new Dictionary<string, string>();

string[] pairs = text.Split(
';',
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries
);

foreach (string pair in pairs)
{
string[] keyValue = pair.Split(
new[] { '=' },
2,
StringSplitOptions.TrimEntries
);

if (keyValue.Length == 2)
{
settings[keyValue[0]] = keyValue[1];
}
}

Console.WriteLine(settings["name"]); // Taro
Console.WriteLine(settings["city"]); // Tokyo

値の中に=が含まれる可能性があるため、count2を指定しています。

6-5. 分割結果をint配列やListに変換する

数値の文字列をint[]に変換する場合は、LINQを使用できます。

C#
using System.Linq;

string text = "10,20,30,40";

int[] numbers = text
.Split(
',',
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries
)
.Select(int.Parse)
.ToArray();

ただし、入力に不正な値が含まれるとint.Parseは例外を投げます。外部入力ではint.TryParseを使うと安全です。

C#
var numbers = new List<int>();

foreach (string part in text.Split(','))
{
if (int.TryParse(part.Trim(), out int number))
{
numbers.Add(number);
}
}

不正な値を検出して処理を中断したい場合は、成功件数を確認します。

C#
string text = "10,abc,30";
var numbers = new List<int>();
bool isValid = true;

foreach (string part in text.Split(','))
{
if (!int.TryParse(part.Trim(), out int number))
{
isValid = false;
Console.WriteLine($"数値に変換できません: {part}");
break;
}

numbers.Add(number);
}

6-6. 分割した要素から必要な値だけを取得する

分割結果から特定位置の値を取り出す場合は、要素数を確認します。

C#
string text = "2026-06-20";
string[] parts = text.Split('-');

if (parts.Length == 3)
{
string year = parts[0];
string month = parts[1];
string day = parts[2];

Console.WriteLine($"{year}年{month}月{day}日");
}

条件に一致する要素だけを取得することもできます。

C#
using System.Linq;

string text = "apple,banana,avocado,orange";

string[] values = text
.Split(',')
.Where(value => value.StartsWith("a"))
.ToArray();

最初に一致した要素だけが必要なら、FirstOrDefaultを使用できます。

C#
string? value = text
.Split(',')
.FirstOrDefault(item => item.StartsWith("b"));

7. Splitで正規表現を使って分割する方法

7-1. String.SplitとRegex.Splitの違い

String.Splitは、決まった文字や文字列を区切りとして分割する場合に適しています。

C#
string[] values = text.Split(',');

一方、区切り条件をパターンで表したい場合は、System.Text.RegularExpressions.Regex.Splitを使用します。

C#
using System.Text.RegularExpressions;

string[] values = Regex.Split(text, @"\s+");

Regex.Splitは、正規表現に一致した位置で文字列を分割し、string[]を返します。Microsoft Learn

単純なカンマやスペースで分割するだけなら、通常はString.Splitの方がコードが分かりやすく、正規表現の解析コストもありません。

7-2. 複数の空白や連続した区切り文字で分割する

\s+を使用すると、1文字以上連続する空白文字で分割できます。

C#
using System.Text.RegularExpressions;

string text = "C# Split\tRegex\nSample";
string[] words = Regex.Split(text.Trim(), @"\s+");

foreach (string word in words)
{
Console.WriteLine(word);
}

実行結果は次のとおりです。

C#
Split
Regex
Sample

半角スペースだけでなく、タブや改行なども\sに一致します。

複数の記号が連続する部分で分割する場合は、文字クラスを使用できます。

C#
string text = "A,,;B:::C";
string[] values = Regex.Split(text, @"[,;:]+");

このパターンでは、カンマ、セミコロン、コロンのいずれかが1文字以上続く部分を1つの区切りとして扱います。

7-3. 数字や記号を条件に文字列を分割する

数字が連続する部分で分割する例です。

C#
using System.Text.RegularExpressions;

string text = "商品123価格456在庫";
string[] values = Regex.Split(text, @"\d+");

foreach (string value in values)
{
Console.WriteLine(value);
}

実行結果は次のとおりです。

商品
価格
在庫

ハイフンまたはスラッシュで分割する場合は、文字クラスを使用します。

C#
string date = "2026/06-20";
string[] parts = Regex.Split(date, @"[-/]");

複数種類の記号が連続する可能性があるなら、+を付けます。

C#
string[] parts = Regex.Split(date, @"[-/]+");

7-4. 区切り文字を分割結果に残す方法

Regex.Splitでは、正規表現のキャプチャグループを使用すると、区切り文字を結果に含められます。

C#
using System.Text.RegularExpressions;

string text = "A+B-C";
string[] parts = Regex.Split(text, @"([+-])");

foreach (string part in parts)
{
Console.WriteLine($"[{part}]");
}

実行結果は次のとおりです。

[A]
[+]
[B]
[-]
[C]

([+-])の丸括弧がキャプチャグループです。区切り文字も後続処理で必要な場合に利用できます。

7-5. Regex.Splitを使うべきケースと注意点

Regex.Splitが適しているのは、次のようなケースです。

  • 連続する空白を1つの区切りとして扱う

  • 数字の並びを区切り条件にする

  • 複数の記号をパターンで指定する

  • 区切り文字を結果に残す

  • 条件の異なる複雑な区切り位置を表現する

一方、単純な1文字の区切りにはString.Splitが適しています。

C#
// 単純な条件ではString.Split
string[] values = text.Split(',');

// パターンが必要な場合はRegex.Split
string[] words = Regex.Split(text, @"\s+");

正規表現のパターンを外部入力から直接組み立てると、意図しない一致や過度に重い処理につながる可能性があります。固定パターンを使う、入力を検証する、必要に応じてタイムアウトを設定するなどの対策を行ってください。

8. Splitを使わずに文字列を分割する方法

8-1. SubstringとIndexOfで特定位置を分割する

区切り文字が最初に現れる位置だけで分割したい場合は、IndexOfSubstringを使えます。

C#
string text = "name=Taro=extra";
int index = text.IndexOf('=');

if (index >= 0)
{
string key = text.Substring(0, index);
string value = text.Substring(index + 1);

Console.WriteLine(key); // name
Console.WriteLine(value); // Taro=extra
}

IndexOfは、指定した文字が見つからない場合に-1を返します。必ず結果を確認してからSubstringを呼び出してください。

8-2. 範囲演算子とRangeで文字列を切り出す

比較的新しいC#では、範囲演算子..を使って簡潔に記述できます。

C#
string text = "name=Taro";
int index = text.IndexOf('=');

if (index >= 0)
{
string key = text[..index];
string value = text[(index + 1)..];

Console.WriteLine(key); // name
Console.WriteLine(value); // Taro
}

text[..index]は先頭からindexの直前まで、text[(index + 1)..]は区切り文字の次から末尾までを表します。

末尾からの位置は^で指定できます。

C#
string text = "sample.txt";
string extension = text[^3..];

Console.WriteLine(extension); // txt

8-3. Spanを使ってメモリ割り当てを抑える

String.Splitは、結果用の配列と各部分文字列を作成します。大量の文字列を繰り返し処理する場面では、ReadOnlySpan<char>を使うことで、一時的な文字列の生成を抑えられます。

C#
ReadOnlySpan<char> remaining = "red,green,blue".AsSpan();

while (true)
{
int index = remaining.IndexOf(',');

ReadOnlySpan<char> item =
index >= 0 ? remaining[..index] : remaining;

// 実際の処理では、可能な限りSpanのまま扱う
Console.WriteLine(item.ToString());

if (index < 0)
{
break;
}

remaining = remaining[(index + 1)..];
}

この例では表示のためにToStringを呼んでいるため、その時点で文字列が生成されます。数値への変換や比較などをSpanのまま行えば、割り当てを減らせます。

新しい.NETには、ReadOnlySpan<T>を分割して範囲を列挙するためのMemoryExtensions.Split関連APIも用意されています。利用できるオーバーロードは、対象とする.NETのバージョンを確認してください。Microsoft Learn+2Microsoft Learn+2

8-4. 区切り文字が1つだけの場合に適した方法を選ぶ

最初の区切り文字で前後に分けるだけなら、IndexOfが適しています。

C#
int index = text.IndexOf(':');

複数の要素へ分割してすべて保持するなら、Splitが分かりやすい選択です。

C#
string[] values = text.Split(':');

大量データを高頻度で処理し、割り当てを最小限にしたい場合は、ReadOnlySpan<char>を検討します。

選択の目安は次のとおりです。

条件適した方法
単純に全要素へ分割するString.Split
最初の区切り位置だけ必要IndexOfと範囲演算子
複雑なパターンで分割するRegex.Split
メモリ割り当てを抑えたいReadOnlySpan<char>
URLやパスを解析するUriPathなど専用API

9. Splitを使用するときの注意点とエラー対策

9-1. 区切り文字が存在しない場合の戻り値

区切り文字が見つからない場合、Splitは元の文字列を1つだけ含む配列を返します。

C#
string text = "apple";
string[] values = text.Split(',');

Console.WriteLine(values.Length); // 1
Console.WriteLine(values[0]); // apple

区切り文字がないからといって、空配列が返るわけではありません。

C#
if (values.Length == 1)
{
Console.WriteLine("区切り文字がない可能性があります。");
}

ただし、元の文字列自体に区切り文字が存在しないことを確実に判定するなら、ContainsIndexOfを使います。

C#
if (!text.Contains(','))
{
Console.WriteLine("カンマが含まれていません。");
}

9-2. nullや空文字を分割するときの挙動

nullの変数に対してSplitを呼び出すと、NullReferenceExceptionが発生します。

C#
string? text = null;

// NullReferenceException
string[] values = text.Split(',');

事前にnullを確認してください。

C#
if (text is not null)
{
string[] values = text.Split(',');
}

空文字列を許容する場合は、null合体演算子を使用できます。

C#
string[] values = (text ?? string.Empty).Split(',');

空文字列をデフォルト設定で分割すると、空文字列を1つ含む配列になります。

C#
string text = "";
string[] values = text.Split(',');

Console.WriteLine(values.Length); // 1
Console.WriteLine(values[0] == ""); // True

RemoveEmptyEntriesを指定すると、結果は空配列になります。

C#
string[] values = text.Split(
',',
StringSplitOptions.RemoveEmptyEntries
);

Console.WriteLine(values.Length); // 0

9-3. 配列の範囲外アクセスを防ぐ方法

分割結果の要素数を確認せずにアクセスすると、IndexOutOfRangeExceptionが発生することがあります。

C#
string text = "name";
string[] parts = text.Split('=');

// parts[1]は存在しない
Console.WriteLine(parts[1]);

安全に処理するには、Lengthを確認します。

C#
if (parts.Length >= 2)
{
Console.WriteLine(parts[1]);
}
else
{
Console.WriteLine("値が指定されていません。");
}

キーと値のように、2要素である必要がある場合は、要素数を厳密に確認します。

C#
if (parts.Length != 2)
{
Console.WriteLine("形式が正しくありません。");
return;
}

ElementAtOrDefaultを使う方法もあります。

C#
using System.Linq;

string? value = parts.ElementAtOrDefault(1);

ただし、必要な要素がなかったことを見落とさないよう、入力形式の検証も行ってください。

9-4. 全角・半角の区切り文字を混同しない

半角カンマ,と全角カンマは異なる文字です。

C#
string text = "東京,大阪,名古屋";
string[] values = text.Split(',');

Console.WriteLine(values.Length); // 1

全角カンマも分割条件に含める場合は、両方を指定します。

C#
char[] separators = { ',', ',' };

string[] values = text.Split(
separators,
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries
);

スペースにも半角スペースと全角スペースがあります。

C#
char[] spaces = { ' ', ' ' };

ユーザー入力を処理する場合は、想定される表記ゆれを洗い出しておきましょう。

9-5. WindowsとLinuxで異なる改行コードに対応する

代表的な改行コードは次のとおりです。

環境・形式改行コード
Windows\r\n
Linux・一般的なUnix系環境\n
古いMac形式など\r

異なる環境で作成されたテキストを扱う場合は、すべてを指定できます。

C#
string[] lines = text.Split(
new[] { "\r\n", "\n", "\r" },
StringSplitOptions.None
);

空行を削除したい場合は、RemoveEmptyEntriesを指定します。

C#
string[] lines = text.Split(
new[] { "\r\n", "\n", "\r" },
StringSplitOptions.RemoveEmptyEntries
);

空行に意味がある文章や設定ファイルでは、削除しないよう注意してください。

9-6. CSVの引用符や区切り文字を含む値は単純なSplitで処理しない

次のCSVでは、2列目の値にカンマが含まれています。

1001,"東京都千代田区,丸の内",5000

これを単純に分割すると、4要素になります。

C#
string[] values = line.Split(',');

CSVでは、引用符のエスケープ、引用符内の改行、区切り文字を含む値などを考慮する必要があります。

1001,"彼は""こんにちは""と言った",5000

このようなデータは、CSV仕様に対応したパーサーで処理してください。単純なSplitが適しているのは、値の中に区切り文字や引用符が含まれないことが保証されている場合です。

10. Splitに関するよくある質問

10-1. Splitの結果から空文字を削除するには?

StringSplitOptions.RemoveEmptyEntriesを指定します。

C#
string text = "A,,B,";

string[] values = text.Split(
',',
StringSplitOptions.RemoveEmptyEntries
);

空白だけの要素も削除したい場合は、TrimEntriesと組み合わせます。

C#
StringSplitOptions options =
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries;

string[] values = text.Split(',', options);

10-2. 複数の区切り文字を同時に指定するには?

1文字の区切り文字を複数指定する場合は、char[]を使用します。

C#
char[] separators = { ',', ';', '|' };
string[] values = text.Split(separators);

複数文字の区切り文字を含む場合は、string[]を使用します。

C#
string[] separators = { "::", "--", "||" };

string[] values = text.Split(
separators,
StringSplitOptions.None
);

10-3. 連続するスペースを1つの区切りとして扱うには?

空要素を除外するだけなら、String.SplitRemoveEmptyEntriesを使います。

C#
string text = "C#   Split   Sample";

string[] words = text.Split(
' ',
StringSplitOptions.RemoveEmptyEntries
);

タブや改行も含めた連続する空白文字を1つの区切りとして扱うなら、Regex.Split\s+が便利です。

C#
using System.Text.RegularExpressions;

string[] words = Regex.Split(
text.Trim(),
@"\s+"
);

10-4. 区切り文字を残したまま分割するには?

String.Splitでは、区切り文字は結果から削除されます。

区切り文字を残すには、Regex.Splitでキャプチャグループを使用します。

C#
using System.Text.RegularExpressions;

string text = "A+B-C";
string[] parts = Regex.Split(text, @"([+-])");

結果は次のとおりです。

A
+
B
-
C

単純な条件であれば、IndexOfを使って区切り位置を取得し、必要な部分を手動で切り出す方法もあります。

10-5. 分割した文字列を再び結合するには?

string.Joinを使用します。

C#
string[] values = { "apple", "orange", "banana" };

string text = string.Join(",", values);

Console.WriteLine(text);

実行結果は次のとおりです。

apple,orange,banana

分割後に空白を整えてから再結合することもできます。

C#
string source = " apple, orange ,banana ";

string[] values = source.Split(
',',
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries
);

string result = string.Join(", ", values);

Console.WriteLine(result);

実行結果は次のとおりです。

apple, orange, banana

10-6. SplitとRegex.Splitはどちらを使うべき?

固定された文字や文字列で分割するなら、String.Splitを使用します。

C#
string[] values = text.Split(',');

連続する空白、数字、複数種類の記号など、パターンで区切り位置を表現する必要がある場合は、Regex.Splitが適しています。

C#
string[] values = Regex.Split(text, @"\s+");

まずString.Splitで表現できるかを確認し、表現できない複雑な条件に限ってRegex.Splitを使うと、コードが読みやすくなります。

10-7. 大量の文字列を高速に分割するには?

大量データを処理するときは、次の点を確認します。

まず、単純な区切り条件に正規表現を使わないことが重要です。

C#
// 単純なカンマ区切り
string[] values = text.Split(',');

次に、分割結果のすべてが必要かを確認します。最初の区切り位置だけ必要なら、IndexOfを使うことで配列の生成を避けられます。

C#
int index = text.IndexOf('=');

if (index >= 0)
{
ReadOnlySpan<char> source = text.AsSpan();
ReadOnlySpan<char> key = source[..index];
ReadOnlySpan<char> value = source[(index + 1)..];
}

また、次のような対策も有効です。

  • 不要なToArrayToListを避ける

  • 分割後すぐに文字列を再生成しない

  • 数値はReadOnlySpan<char>から直接解析する

  • ファイル全体を一度に分割せず、1行ずつ処理する

  • 頻繁に実行される処理では、ベンチマークで比較する

  • 複雑な正規表現は使い回し、毎回作成しない

  • 必要に応じてSpanベースのAPIを利用する

通常の業務アプリケーションでは、まず読みやすいString.Splitを使用し、実測で性能上の問題が確認された部分だけを最適化するのが適切です。

まとめ

C#で文字列を分割する基本的な方法は、String.Splitメソッドを使用することです。

1文字の区切り文字なら、charを指定します。

C#
string[] values = text.Split(',');

複数種類の区切り文字なら、char[]を使用します。

C#
string[] values = text.Split(
new[] { ',', ';', '|' },
StringSplitOptions.None
);

::--のような複数文字の区切り文字には、string[]を使用します。

C#
string[] values = text.Split(
new[] { "::", "--" },
StringSplitOptions.None
);

空要素と前後の空白を削除する場合は、RemoveEmptyEntriesTrimEntriesを組み合わせます。

C#
StringSplitOptions options =
StringSplitOptions.RemoveEmptyEntries |
StringSplitOptions.TrimEntries;

string[] values = text.Split(',', options);

最初の区切り文字だけで分割したい場合は、count2を指定します。

C#
string[] parts = text.Split(
new[] { '=' },
2,
StringSplitOptions.TrimEntries
);

連続する空白や複雑なパターンで分割するときはRegex.Split、最初の区切り位置だけ必要な場合はIndexOf、メモリ割り当てを抑えたい場合はReadOnlySpan<char>が選択肢になります。

ただし、CSV、URL、ファイルパスなど、独自の構文や規則を持つデータは、単純なSplitだけで処理せず、UriPath、CSVパーサーなどの用途に合った方法を選ぶことが重要です。