C# Tips | 文字列処理:文字列分割

C# C#
スポンサーリンク

はじめに 「文字列分割」は“バラしてから意味をつける”ための基本技

業務システムでは、「1本の文字列の中に、複数の値が詰め込まれている」ことがよくあります。
CSV の 1 行、区切り文字付きの設定値、ユーザーが入力した「A,B,C」形式のリストなどです。

こういうときに必ず使うのが「文字列分割」です。
C# には string.Split という強力なメソッドがありますが、そのまま使うと「空要素が混ざる」「空白が残る」「null で落ちる」など、地味なトラブルが起きがちです。

ここでは、初心者向けに、

string.Split の基本
よくある落とし穴(空要素・空白・null)
実務で使える「安全な分割ユーティリティ」
カンマ区切り・改行区切りなどの具体例

を、かみ砕いて解説していきます。


string.Split の基本を押さえる

一番シンプルな使い方

まずは、素の Split から見てみます。

string s = "A,B,C";

string[] parts = s.Split(',');

foreach (var p in parts)
{
    Console.WriteLine($"[{p}]");
}
C#

出力はこうなります。

[A]
[B]
[C]

カンマ , を区切り文字として、"A", "B", "C" に分割されています。
ここまでは直感通りで分かりやすいですね。

区切り文字は複数指定できる

Split は、区切り文字を複数指定することもできます。

string s = "A,B;C D";

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

string[] parts = s.Split(separators);

foreach (var p in parts)
{
    Console.WriteLine($"[{p}]");
}
C#

この場合、カンマ・セミコロン・スペースのどれかが来たら区切る、という動きになります。

ただし、このままだと「空文字要素」が混ざりやすい、という問題が出てきます。


重要ポイント① 空要素をどう扱うか

そのまま Split すると“空のかけら”が混ざる

例えば、こんな文字列を考えます。

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

このときの parts の中身はこうなります。

"A"
""(A と B の間の連続カンマ)
"B"
" "(スペースだけ)
"C"
""(末尾のカンマ)

多くの場合、「空文字」や「空白だけ」の要素は要りません。
でも、素の Split は容赦なくそれらも配列に入れてきます。

これを放置すると、

要素数を数えたときにズレる
ループ処理で余計なケース分けが増える
「空文字なのに値があると勘違いする」バグが出る

といった地味なトラブルにつながります。

StringSplitOptions で空要素を除外する

ここで使いたいのが StringSplitOptions です。

string s = "A,,B, ,C,";

string[] parts = s.Split(
    new[] { ',' },
    StringSplitOptions.RemoveEmptyEntries);

foreach (var p in parts)
{
    Console.WriteLine($"[{p}]");
}
C#

RemoveEmptyEntries を指定すると、「区切り文字の間に何もないところ」は結果から除外されます。
この例だと、"" の要素は消えますが、" "(スペースだけ)は残ります。

つまり、

「本当に空の要素」は消える
「空白だけの要素」は残る

という挙動です。

実務では、「空白だけも要らない」ことが多いので、ここにもう一手間加えます。


重要ポイント② トリムと組み合わせて“きれいな配列”にする

分割後に Trim する

「空白だけの要素も消したい」「前後の空白を落としたい」という場合、
分割したあとに Trim() をかけて整えるのが定番です。

using System;
using System.Collections.Generic;

public static class SplitUtil
{
    public static string[] SplitAndTrim(
        string? value,
        char separator,
        bool removeEmpty = true)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return Array.Empty<string>();
        }

        string[] raw = value.Split(
            new[] { separator },
            removeEmpty ? StringSplitOptions.RemoveEmptyEntries
                        : StringSplitOptions.None);

        var list = new List<string>(raw.Length);

        foreach (string item in raw)
        {
            string trimmed = item.Trim();

            if (removeEmpty && trimmed.Length == 0)
            {
                continue;
            }

            list.Add(trimmed);
        }

        return list.ToArray();
    }
}
C#

ここでやっていることを整理します。

null や空白だけの文字列が来たら、空配列を返す。
Split で一旦分割する(空要素を除外するかどうかは引数で制御)。
各要素に Trim() をかけて前後の空白を削る。
removeEmpty が true の場合、トリム後に空文字になった要素は捨てる。

これで、「空要素」「空白だけの要素」「前後に空白が付いた要素」をきれいに処理できます。

具体例で動きを確認する

Console.WriteLine("---- 1 ----");
foreach (var x in SplitUtil.SplitAndTrim("A,B,C", ',', true))
{
    Console.WriteLine($"[{x}]"); // [A][B][C]
}

Console.WriteLine("---- 2 ----");
foreach (var x in SplitUtil.SplitAndTrim("A,,B, ,C,", ',', true))
{
    Console.WriteLine($"[{x}]"); // [A][B][C]
}

Console.WriteLine("---- 3 ----");
foreach (var x in SplitUtil.SplitAndTrim(" A , B , C ", ',', true))
{
    Console.WriteLine($"[{x}]"); // [A][B][C]
}
C#

「入力が多少汚れていても、結果はきれいな配列になる」という状態を作っておくと、
後続の処理がかなり楽になります。


重要ポイント③ null をどう扱うか

そのまま Split を呼ぶと NullReferenceException

よくあるパターンがこれです。

string? s = GetFromConfig(); // null かもしれない

string[] parts = s.Split(','); // s が null だと落ちる
C#

Split はインスタンスメソッドなので、レシーバーが null だと NullReferenceException になります。

実務では「null かもしれない文字列」は山ほど出てくるので、
分割処理も「null 安全」にしておくと安心です。

null のときは「空配列」を返す設計

先ほどの SplitAndTrim では、最初にこうしていました。

if (string.IsNullOrWhiteSpace(value))
{
    return Array.Empty<string>();
}
C#

string.IsNullOrWhiteSpace は、

null
空文字 ""
空白だけ " "

をまとめて「中身なし」とみなしてくれます。

ここで「空配列を返す」というルールにしておくと、呼び出し側はこう書けます。

string? raw = GetFromConfig();

foreach (var item in SplitUtil.SplitAndTrim(raw, ',', true))
{
    // null かどうかを気にせず回せる
}
C#

「null かもしれない」「空文字かもしれない」を毎回 if でチェックしなくてよくなるので、
コードがかなりスッキリします。


カンマ区切りの“IDリスト”を扱うユーティリティ例

よくある「ID のカンマ区切り」を安全にパースする

業務で本当によく出てくるのが、「ID をカンマ区切りで持っている」パターンです。

"1,2,3"
" 10 , 20 , 30 "
"1,,2, ,3"

これを int[] に変換したいとき、
Splitint.Parse をそのまま組み合わせると、すぐに例外祭りになります。

ここは、分割とトリムと数値変換をまとめたユーティリティを用意してしまうのがおすすめです。

using System;
using System.Collections.Generic;

public static class IdListParser
{
    public static int[] ParseIntList(string? value, char separator = ',')
    {
        string[] parts = SplitUtil.SplitAndTrim(value, separator, removeEmpty: true);

        var list = new List<int>(parts.Length);

        foreach (string p in parts)
        {
            if (int.TryParse(p, out int id))
            {
                list.Add(id);
            }
            else
            {
                // 数値に変換できないものは無視するか、例外にするかは要件次第
                // ここでは「無視する」方針にしている
            }
        }

        return list.ToArray();
    }
}
C#

使い方の例です。

foreach (var id in IdListParser.ParseIntList("1,2,3"))
{
    Console.WriteLine(id); // 1 2 3
}

foreach (var id in IdListParser.ParseIntList(" 10 , , 20 , x , 30 "))
{
    Console.WriteLine(id); // 10 20 30
}
C#

ここまでやっておくと、

空要素
空白
変な文字

を全部吸収したうえで、「まともな ID だけの配列」が手に入ります。


改行区切り・タブ区切りなどへの応用

区切り文字を変えるだけで応用できる

SplitAndTrim は、区切り文字を引数で受け取るようにしてあるので、
カンマ以外にも簡単に応用できます。

改行区切りのリスト。

string s = "A\nB\r\nC";

string[] lines = SplitUtil.SplitAndTrim(s, '\n', true);
// あるいは Environment.NewLine を意識した実装にしてもよい
C#

タブ区切りの値。

string s = "A\tB\tC";

string[] cols = SplitUtil.SplitAndTrim(s, '\t', true);
C#

もし「複数種類の区切り文字」を扱いたい場合は、
char separatorchar[] separators に変えて、Split の呼び出しを少し変えれば対応できます。


まとめ 「文字列分割ユーティリティ」は“汚い入力をきれいな配列に変えるフィルタ”

文字列分割は、単に Split を呼ぶだけではなく、

空要素
空白だけの要素
前後の空白
null

といった“現実の汚れ”をどう扱うかまで含めて設計すると、一気に実務レベルになります。

押さえておきたいポイントはこうです。

string.Split はそのままだと空要素を含むので、StringSplitOptions.RemoveEmptyEntries を意識する。
分割後に Trim() をかけて、前後の空白や「空白だけの要素」を整理すると、後続処理が楽になる。
null や空白だけの入力は、「空配列を返す」ユーティリティにしておくと、呼び出し側の if が減る。
カンマ区切りの ID リストなど、よく出るパターンは「分割+トリム+型変換」をまとめた専用ユーティリティにしてしまうと強い。

ここまでできれば、「とりあえず Split してるだけ」の段階から抜け出して、
“汚い文字列をきれいな配列に変えるフィルタ”として、文字列分割を設計できるようになります。

タイトルとURLをコピーしました