C# Tips | 文字列操作:文字列を指定文字数で切る

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

文字列を指定文字数で切るとは?

C#で文字列を扱うとき、指定した文字数だけを取り出したい場面があります。例えば、長い商品名を一覧画面で短く表示したい場合や、ログの内容を一定の長さに制限したい場合、入力された文字列の先頭部分だけを取得したい場合などです。

このような処理は、文字列の切り出しと呼ばれます。

C#では、文字列の一部を取り出すために、主にSubstring()や範囲指定の構文を使用します。また、文字列の長さを調べるにはLengthプロパティを使用します。

例えば、次のコードでは、文字列の先頭から5文字を取り出しています。

using System;

class Program
{
    static void Main()
    {
        // 切り出し元の文字列
        string text = "こんにちは世界";

        // 先頭から5文字を取り出す
        string result = text.Substring(0, 5);

        // 結果を表示する
        Console.WriteLine(result); // こんにちは
    }
}
C#

Substring(0, 5)は、文字列の先頭を表す位置0から、5文字を取り出すという意味です。

文字列の位置は、基本的に0から数え始めます。最初の文字の位置が0、2文字目の位置が1、3文字目の位置が2となります。

ただし、指定した文字数で文字列を切り出す処理では、文字列が短い場合の扱いや、nullへの対応、絵文字などの特殊な文字の扱いに注意する必要があります。

この記事では、初心者向けに基本的な切り出し方から解説し、実務で使いやすい共通メソッド、安全な実装方法、文字列の長さに関する注意点、テスト方法まで順番に説明します。

C#で文字列の長さを調べる

Lengthプロパティの基本

文字列を指定した長さで切る前に、まず文字列の長さを調べる方法を理解しましょう。

C#では、文字列の長さをLengthプロパティで取得できます。

using System;

class Program
{
    static void Main()
    {
        // 文字列を用意する
        string text = "Hello";

        // 文字列の長さを取得する
        int length = text.Length;

        // 結果を表示する
        Console.WriteLine(length); // 5
    }
}
C#

この例では、Helloは5文字なので、Lengthの結果は5になります。

Lengthは、文字列の長さを確認したい場合や、切り出す文字数が適切かどうかを判定したい場合に使用します。

ただし、C#のstring.Lengthは、厳密には人間が数える文字数ではなく、UTF-16のコード単位数を返します。一般的な英数字や日本語の多くは1文字につき1ですが、絵文字などでは2以上になる場合があります。

この違いについては、後半の注意点で詳しく説明します。

文字列の位置は0から始まる

C#の文字列操作では、位置を0から数えることが重要です。

例えば、次の文字列を考えます。

// 文字列を用意する
string text = "ABCDE";

それぞれの文字の位置は、次のようになります。

位置文字
0A
1B
2C
3D
4E

この文字列から先頭の3文字を取り出す場合は、位置0から3文字を指定します。

// 先頭から3文字を取り出す
string result = text.Substring(0, 3);

// 結果:ABC
Console.WriteLine(result);
C#

ここで、Substring()の第1引数は開始位置、第2引数は取り出す文字数です。

開始位置と取り出す文字数を混同しないようにしましょう。

Substringで指定文字数を切り出す

基本的な使い方

Substring()は、文字列の一部を取り出すためのメソッドです。

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

// 開始位置から指定した文字数を取り出す
string result = text.Substring(startIndex, length);
C#

それぞれの引数には、次の意味があります。

  • text:切り出し元の文字列
  • startIndex:切り出しを開始する位置
  • length:取り出す文字数

例えば、ABCDEから2文字目のBを含めて3文字を取り出す場合は、開始位置を1、文字数を3に指定します。

using System;

class Program
{
    static void Main()
    {
        // 切り出し元の文字列
        string text = "ABCDE";

        // 位置1から3文字を取り出す
        string result = text.Substring(1, 3);

        // 結果を表示する
        Console.WriteLine(result); // BCD
    }
}
C#

Substring(1, 3)は、位置1のBから始まり、合計3文字を取り出します。

開始位置が1だからといって、1文字だけ取り出すという意味ではありません。開始位置と文字数は別々に指定します。

先頭から指定文字数を取り出す

文字列の先頭から指定した文字数を取り出す場合は、開始位置に0を指定します。

using System;

class Program
{
    static void Main()
    {
        // 商品名を用意する
        string productName = "高性能ワイヤレスマウス";

        // 先頭から5文字を取り出す
        string shortName = productName.Substring(0, 5);

        // 結果を表示する
        Console.WriteLine(shortName); // 高性能ワイヤ
    }
}
C#

この方法は、商品名やタイトルの先頭部分を取り出す処理などに利用できます。

ただし、文字列が5文字未満の場合には、そのままSubstring(0, 5)を呼び出すと例外が発生します。実務では、切り出し元の長さを確認することが重要です。

文字列が短くても安全に切り出す

文字列が指定文字数より短い場合の問題

例えば、先頭から10文字を取り出したいとします。

// 文字列は5文字しかない
string text = "Hello";

// 10文字を取り出そうとすると例外が発生する
string result = text.Substring(0, 10);
C#

このコードでは、ArgumentOutOfRangeExceptionが発生します。

なぜなら、文字列には5文字しかないのに、10文字を取り出そうとしているからです。

外部ファイルやユーザー入力などから取得した文字列は、必ずしも想定した長さとは限りません。そのため、文字列の長さを確認せずに切り出すと、実行時エラーにつながる可能性があります。

Lengthを使って安全に切り出す

文字列が指定文字数より短い場合は、文字列全体を返すようにすると安全です。

using System;

class Program
{
    static void Main()
    {
        // 切り出し元の文字列
        string text = "Hello";

        // 取り出したい文字数
        int maxLength = 10;

        // 実際に取り出す文字数を計算する
        int length = Math.Min(text.Length, maxLength);

        // 先頭から安全に切り出す
        string result = text.Substring(0, length);

        // 結果を表示する
        Console.WriteLine(result); // Hello
    }
}
C#

Math.Min()は、2つの値のうち小さいほうを返します。

この例では、text.Lengthが5、maxLengthが10なので、実際に取り出す文字数は5になります。

その結果、文字列が短くても例外が発生せず、文字列全体を取得できます。

ただし、maxLengthが負の数の場合は別途対処が必要です。実務で汎用的なメソッドを作る場合は、引数の範囲も検証しましょう。

実務で使える文字列切り出しメソッドを作る

先頭から指定文字数を安全に取得する

複数の場所で同じ処理を使う場合は、共通メソッドにまとめると便利です。

ここでは、先頭から指定した文字数を取り出し、文字列が短い場合は存在する部分だけを返すメソッドを作成します。

using System;

public static class StringUtility
{
    /// <summary>
    /// 文字列の先頭から指定した文字数を安全に取得します。
    /// </summary>
    /// <param name="text">切り出し元の文字列</param>
    /// <param name="maxLength">取得する最大文字数</param>
    /// <returns>先頭から切り出した文字列。入力がnullの場合はnull。</returns>
    public static string TakeText(string text, int maxLength)
    {
        // nullの場合はnullをそのまま返す
        if (text == null)
        {
            return null;
        }

        // 負の文字数は許可しない
        if (maxLength < 0)
        {
            throw new ArgumentOutOfRangeException(
                nameof(maxLength),
                "文字数は0以上を指定してください。");
        }

        // 実際に取り出す文字数を求める
        int length = Math.Min(text.Length, maxLength);

        // 先頭から指定文字数を取得する
        return text.Substring(0, length);
    }
}

class Program
{
    static void Main()
    {
        // 長い文字列
        string text1 = "高性能ワイヤレスマウス";

        // 短い文字列
        string text2 = "Hello";

        // 先頭から5文字を取得する
        Console.WriteLine(StringUtility.TakeText(text1, 5));

        // 文字列が短い場合は全体を返す
        Console.WriteLine(StringUtility.TakeText(text2, 10));

        // 0文字を指定すると空文字列を返す
        Console.WriteLine(StringUtility.TakeText(text2, 0));
    }
}
C#

このメソッドでは、次の順番で処理しています。

  1. 入力値がnullかどうかを確認します。
  2. 指定文字数が負の数でないことを確認します。
  3. 文字列の長さと指定文字数を比較します。
  4. 小さいほうの値を実際の切り出し文字数にします。
  5. Substring()で先頭から切り出します。

このように、入力値を確認してから文字列を操作することで、想定外の入力による例外を防ぎやすくなります。

なお、この実装では、nullの場合にnullを返す設計にしています。入力が必須の処理であれば、nullを返す代わりに例外を発生させる方法もあります。アプリケーションの仕様に合わせて選択してください。

C#の範囲指定を使う方法

C# 8.0以降では、範囲指定の構文を使って文字列の一部を取り出すこともできます。

例えば、先頭から5文字を取り出す場合は、次のように書けます。

using System;

class Program
{
    static void Main()
    {
        // 切り出し元の文字列
        string text = "ABCDEFGHIJ";

        // 先頭から5文字を取得する
        string result = text[..5];

        // 結果を表示する
        Console.WriteLine(result); // ABCDE
    }
}
C#

[..5]は、先頭から位置5の直前までを取り出すという意味です。位置5の文字は含まれないため、取得できるのは先頭の5文字です。

同じ処理をSubstring()で書くと、次のようになります。

// Substringを使う方法
string result1 = text.Substring(0, 5);

// 範囲指定を使う方法
string result2 = text[..5];
C#

どちらも先頭から5文字を取得できます。

範囲指定は短く書けるため便利ですが、利用するC#のバージョンに注意してください。古い開発環境では使用できない場合があります。

また、text[..5]も、文字列が5文字未満なら例外になります。短い文字列でも安全に処理したい場合は、事前に長さを確認するか、先ほどの共通メソッドを利用しましょう。

末尾から指定文字数を取得する

文字列の最後の部分を取り出す

文字列の末尾から指定した文字数を取得したい場合もあります。例えば、ファイル名の末尾や、識別番号の最後の数桁を取り出す場合などです。

Substring()を使う場合は、文字列の長さから取り出したい文字数を引いて開始位置を求めます。

using System;

class Program
{
    static void Main()
    {
        // ファイル名を用意する
        string fileName = "report2026";

        // 末尾から4文字を取得する
        int length = 4;

        // 開始位置を計算する
        int startIndex = fileName.Length - length;

        // 末尾から切り出す
        string result = fileName.Substring(startIndex, length);

        // 結果を表示する
        Console.WriteLine(result); // 2026
    }
}
C#

fileName.Lengthは10なので、開始位置は10 - 4 = 6です。位置6から4文字を取り出すことで、2026を取得できます。

ただし、文字列が指定文字数より短い場合や、指定文字数が負の数の場合には注意が必要です。末尾から切り出す共通メソッドを作る場合も、先頭からの切り出しと同様に入力値を検証しましょう。

末尾から安全に取得するメソッド

次の例では、文字列が短い場合は全体を返し、指定文字数が負の数なら例外を発生させます。

using System;

public static class StringUtility
{
    /// <summary>
    /// 文字列の末尾から指定した文字数を安全に取得します。
    /// </summary>
    /// <param name="text">切り出し元の文字列</param>
    /// <param name="maxLength">取得する最大文字数</param>
    /// <returns>末尾から切り出した文字列。入力がnullの場合はnull。</returns>
    public static string TakeLastText(string text, int maxLength)
    {
        // nullの場合はnullを返す
        if (text == null)
        {
            return null;
        }

        // 負の文字数は許可しない
        if (maxLength < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(maxLength));
        }

        // 取得する文字数を文字列の長さ以下にする
        int length = Math.Min(text.Length, maxLength);

        // 末尾から取得するための開始位置を計算する
        int startIndex = text.Length - length;

        // 指定位置から切り出す
        return text.Substring(startIndex, length);
    }
}

class Program
{
    static void Main()
    {
        // 対象の文字列
        string text = "ABCDEFGHIJ";

        // 末尾から4文字を取得する
        string result = StringUtility.TakeLastText(text, 4);

        // 結果を表示する
        Console.WriteLine(result); // GHIJ
    }
}
C#

このメソッドでは、先に取得する文字数を決めてから開始位置を計算しています。これにより、文字列が指定文字数より短い場合でも、開始位置が負の数になることを防げます。

文字列の途中から指定文字数を取得する

開始位置と文字数を指定する

先頭や末尾だけでなく、文字列の途中から一定の長さを取得したい場合は、Substring()の開始位置と文字数を指定します。

例えば、注文番号の一部を取り出す場合です。

using System;

class Program
{
    static void Main()
    {
        // 注文番号を用意する
        string orderId = "ORD-2026-12345";

        // 位置4から4文字を取得する
        string year = orderId.Substring(4, 4);

        // 結果を表示する
        Console.WriteLine(year); // 2026
    }
}
C#

この例では、位置4から4文字を取り出しています。

ただし、固定位置で切り出す方法は、入力データの形式が決まっている場合に向いています。注文番号の形式が変わったり、入力値が短かったりすると、誤った部分を取得したり例外が発生したりする可能性があります。

実務では、固定位置で切り出す前に、入力形式を検証することも重要です。

文字列を指定文字数で切って省略記号を付ける

一覧画面で長い文字列を短く表示する

実務では、文字列を指定文字数で切るだけでなく、長すぎる場合に省略記号を付けたいこともあります。

例えば、商品名や記事タイトルを一覧画面で表示する場合です。

using System;

class Program
{
    // 長い文字列を指定した最大文字数で短くする
    static string TruncateText(string text, int maxLength)
    {
        // nullの場合はnullを返す
        if (text == null)
        {
            return null;
        }

        // 最大文字数が負の場合はエラーにする
        if (maxLength < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(maxLength));
        }

        // 指定文字数以内なら、そのまま返す
        if (text.Length <= maxLength)
        {
            return text;
        }

        // 指定文字数を超える場合は切り出して省略記号を付ける
        return text.Substring(0, maxLength) + "...";
    }

    static void Main()
    {
        // 商品名を用意する
        string productName = "高性能ワイヤレスマウス";

        // 先頭から6文字に省略記号を付ける
        string result = TruncateText(productName, 6);

        // 結果を表示する
        Console.WriteLine(result); // 高性能ワイヤ...
    }
}
C#

この例では、文字列が指定文字数以内ならそのまま返し、指定文字数を超える場合だけ切り出して...を付けています。

ただし、ここでのmaxLengthは切り出す本文の文字数です。省略記号の3文字を含めた最終的な文字列の長さは、最大でmaxLength + 3になります。

省略記号も含めて全体の長さを指定文字数以内にしたい場合は、切り出す文字数を調整する必要があります。

省略記号も含めて最大文字数に収める

例えば、全体を最大10文字に収めたい場合、末尾の...に3文字を使うので、本文は最大7文字にします。

using System;

class Program
{
    // 省略記号を含めて最大文字数以内に収める
    static string TruncateWithEllipsis(string text, int maxLength)
    {
        // nullの場合はnullを返す
        if (text == null)
        {
            return null;
        }

        // 最大文字数が負の場合はエラーにする
        if (maxLength < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(maxLength));
        }

        // 文字列が指定文字数以内なら、そのまま返す
        if (text.Length <= maxLength)
        {
            return text;
        }

        // 最大文字数が3以下なら省略記号だけを切り詰めて返す
        if (maxLength <= 3)
        {
            return new string('.', maxLength);
        }

        // 省略記号の3文字分を除いた長さを求める
        int contentLength = maxLength - 3;

        // 本文を切り出し、省略記号を追加する
        return text.Substring(0, contentLength) + "...";
    }

    static void Main()
    {
        // 長い商品名
        string text = "高性能ワイヤレスマウス";

        // 全体を最大10文字に収める
        string result = TruncateWithEllipsis(text, 10);

        // 結果を表示する
        Console.WriteLine(result);
    }
}
C#

この方法なら、通常の文字列に対して、省略記号を含む結果を指定文字数以内に収められます。

ただし、絵文字などを含む文字列では、LengthやSubstring()が人間の認識する文字数と一致しない場合があります。ユーザー向けの画面で厳密に表示文字数を制御したい場合は、後述するテキスト要素の扱いにも注意してください。

文字列を切り出すときの重要な注意点

nullと空文字列を区別する

C#では、nullと空文字列""は異なります。

  • null:文字列が存在しない状態
  • "":長さが0の文字列

例えば、nullに対してSubstring()を呼び出すと、NullReferenceExceptionが発生します。そのため、外部から取得した文字列を切り出す場合は、必要に応じてnullチェックを行いましょう。

// nullの文字列
string text = null;

// nullチェックをしてから切り出す
if (text != null)
{
    // 先頭から3文字を取得する
    string result = text.Substring(0, Math.Min(text.Length, 3));

    Console.WriteLine(result);
}
else
{
    // nullの場合の処理
    Console.WriteLine("文字列がありません。");
}
C#

nullを空文字列に変換して処理を続ける方法もありますが、入力が存在しなかったことを区別したい場合は、無条件に空文字列へ変換しないようにしてください。

絵文字や特殊な文字に注意する

C#のstring.LengthとSubstring()は、UTF-16のコード単位を基準に処理します。

そのため、一般的な英数字や多くの日本語文字では、1文字が1として扱われますが、絵文字の中には2つのコード単位で表されるものがあります。

例えば、次の文字列です。

using System;

class Program
{
    static void Main()
    {
        // 絵文字を含む文字列
        string text = "A😀B";

        // UTF-16のコード単位数を表示する
        Console.WriteLine(text.Length); // 4

        // 先頭から2コード単位を切り出す
        string result = text.Substring(0, 2);

        // 結果を表示する
        Console.WriteLine(result);
    }
}
C#

A😀Bは、人間が見ている文字としては3つですが、Lengthは4になります。絵文字😀がUTF-16で2コード単位を使用するためです。

この例では、先頭から2コード単位を取り出すことで、Aと絵文字全体が取得されます。しかし、切り出す位置によっては、絵文字を構成するコード単位の途中で切れてしまい、正しく表示できない文字列になる可能性があります。

また、見た目が1文字に見えても、複数のUnicodeコードポイントや結合文字から構成されている場合があります。人間が認識する「1文字」を厳密に扱いたい場合は、単純なLengthやSubstring()だけでは不十分です。

ユーザー向けの表示文字数を正しく制限したい場合は、.NETのSystem.Globalization.StringInfoなどを利用し、テキスト要素単位で処理する方法を検討してください。

文字列を切ることとバイト数を制限することは別

文字列の長さを制限したい理由が、ファイルサイズやデータベースの保存容量、通信データの最大サイズなどに関係する場合は注意が必要です。

Substring()で指定しているのは、文字列の切り出し長です。UTF-8などのエンコーディングで変換したときのバイト数を指定しているわけではありません。

例えば、日本語はUTF-8では一般的に1文字あたり3バイトになることが多く、英数字は通常1バイトです。そのため、文字数が同じでも、エンコーディング後のバイト数は異なる場合があります。

データベースのカラム制限や外部APIのバイト制限に合わせたい場合は、文字列を適切なエンコーディングでバイト列に変換し、バイト数を確認する必要があります。ただし、単純にバイト列を途中で切ると、文字の途中で分断される可能性があるため、文字境界を考慮した実装が必要です。

入力値の検証を忘れない

文字列を切り出すメソッドでは、開始位置や文字数に不正な値が渡される可能性があります。

例えば、次のような指定は問題になります。

// 文字列を用意する
string text = "ABCDE";

// 負の開始位置を指定すると例外が発生する
string result = text.Substring(-1, 2);
C#

Substring()では、開始位置が負の数だったり、指定範囲が文字列の長さを超えたりすると例外が発生します。

実務では、次の点を確認すると安全です。

  • 入力文字列がnullでないか
  • 指定文字数が負の数でないか
  • 開始位置が文字列の範囲内にあるか
  • 指定範囲が文字列の長さを超えていないか
  • 絵文字などの特殊な文字を途中で切らないか
  • 文字数の制限なのか、バイト数の制限なのか

すべての入力値を無条件に受け入れるのではなく、メソッドの目的に合わせて適切に検証することが重要です。

文字列切り出しのテストを作成する

基本的なテストケース

文字列を指定文字数で切り出すメソッドを作成したら、正常なケースだけでなく、境界値も確認しておきましょう。

入力文字列指定文字数期待する結果
"ABCDE"3"ABC"
"Hello"5"Hello"
"Hello"10"Hello"
"Hello"0""
""3""
null3null

また、負の数を指定した場合に例外が発生することも確認するとよいでしょう。

簡単なテストコード

次のコードは、先ほどのTakeText()を使って、基本的な動作を確認する例です。

using System;

class Program
{
    // 先頭から指定文字数を安全に取得する
    static string TakeText(string text, int maxLength)
    {
        // nullの場合はnullを返す
        if (text == null)
        {
            return null;
        }

        // 負の文字数は許可しない
        if (maxLength < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(maxLength));
        }

        // 実際に取り出す文字数を求める
        int length = Math.Min(text.Length, maxLength);

        // 先頭から切り出す
        return text.Substring(0, length);
    }

    static void Main()
    {
        // 入力文字列と指定文字数を用意する
        string text = "ABCDE";

        // 先頭から3文字を取得する
        string result1 = TakeText(text, 3);

        // 文字列の長さを超える数を指定する
        string result2 = TakeText(text, 10);

        // 0文字を指定する
        string result3 = TakeText(text, 0);

        // 結果を表示する
        Console.WriteLine(result1); // ABC
        Console.WriteLine(result2); // ABCDE
        Console.WriteLine($"[{result3}]"); // []
    }
}
C#

境界値のテストを用意しておけば、後から共通メソッドを修正したときにも、想定した動作が維持されているか確認できます。

まとめ

C#で文字列を指定文字数で切り出すには、Substring()が基本となります。先頭から取得する場合はSubstring(0, length)、途中から取得する場合はSubstring(startIndex, length)を使います。

また、C# 8.0以降では、範囲指定の構文を使ってtext[..5]のように記述することもできます。

実務では、次のポイントを押さえておきましょう。

  • 文字列の位置は0から始まります。
  • Substring()の第1引数は開始位置、第2引数は取り出す文字数です。
  • 文字列が指定文字数より短い場合は、Math.Min()などで切り出す長さを調整します。
  • nullや負の文字数など、不正な入力への対応を検討します。
  • 絵文字などでは、Lengthが人間の認識する文字数と一致しない場合があります。
  • 文字数の制限と、エンコーディング後のバイト数の制限は別の問題です。
  • 省略記号を付ける場合は、その文字数を制限に含めるかどうかを明確にします。
  • 共通メソッドにまとめ、短い文字列・空文字列・null・境界値をテストします。

文字列の切り出しは、画面表示やデータ加工など、さまざまな業務処理で利用される基本的な技術です。単にSubstring()を呼び出すだけでなく、入力値の長さや特殊な文字の扱いまで考慮することで、より安全で保守しやすいC#コードを作成できます。

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