C# Tips | 文字列処理:数字のみ抽出

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

はじめに 「数字のみ抽出」は“文字列から数値の芯だけを取り出す”技

業務システムでは、こういう文字列がよく出てきます。

"ID: 12345"
"注文No=AB-2025-00123"
"TEL 03-1234-5678"

人間が見れば「数字の部分はこれだな」とすぐ分かりますが、
プログラムにとっては「ただの文字の並び」です。

ここで欲しいのは、

「文字列の中から“数字だけ”を取り出す、小さくて頼れるユーティリティ」

です。

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

  • 正規表現で数字だけを抜き出す方法
  • LINQ/ループで“1文字ずつ見て数字だけ集める”方法
  • null や空文字に強いユーティリティ化
  • 「全部つなげる」のか「数字の塊ごとに欲しいのか」の違い

を、例題付きでかみ砕いて説明していきます。


アプローチの全体像 「2つの考え方」がある

数字だけを取り出すとき、考え方は大きく分けて 2 つです。

1つ目は、「文字列の中にある“数字の塊”を正規表現で見つける」方法。
2つ目は、「文字列を 1 文字ずつ見て、数字だけを拾い集める」方法。

どちらもよく使いますが、

  • 「とにかく全部の数字をくっつけて 1 本にしたい」なら、2つ目(1文字ずつ)がシンプル。
  • 「数字の塊ごとに分けて扱いたい」なら、1つ目(正規表現)が便利。

この違いを意識しておくと、設計がブレにくくなります。


1. ループで“数字だけを拾い集める”シンプル実装

一番分かりやすい「for ループ版」

まずは、正規表現を使わない、超ストレートなやり方から。

using System;
using System.Text;

public static class DigitExtractor
{
    public static string ExtractDigits(string? value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return string.Empty;
        }

        var sb = new StringBuilder(value.Length);

        foreach (char c in value)
        {
            if (char.IsDigit(c))
            {
                sb.Append(c);
            }
        }

        return sb.ToString();
    }
}
C#

ここでやっていることを、言葉で分解します。

  1. null や空文字が来たら、空文字を返す(例外にしない)。
  2. foreach で 1 文字ずつ見る。
  3. char.IsDigit(c) が true のときだけ StringBuilder に追加する。
  4. 最後に ToString() で文字列に戻す。

char.IsDigit は「その文字が数字かどうか」を判定してくれるメソッドです。
StringBuilder は「何度も文字を追加しても効率が落ちにくい」文字列バッファです。

動作例を見てイメージを固める

Console.WriteLine(DigitExtractor.ExtractDigits("ID: 12345"));          // 12345
Console.WriteLine(DigitExtractor.ExtractDigits("AB-2025-00123"));      // 202500123
Console.WriteLine(DigitExtractor.ExtractDigits("TEL 03-1234-5678"));   // 0312345678
Console.WriteLine(DigitExtractor.ExtractDigits("No digits!"));         // 空文字
Console.WriteLine(DigitExtractor.ExtractDigits(null));                 // 空文字
C#

ポイントは、「数字がどこに散らばっていても、とにかく全部くっつけて返す」という挙動です。

  • "AB-2025-00123""202500123"
  • "TEL 03-1234-5678""0312345678"

のように、「数字の塊ごと」ではなく「数字だけ全部」を 1 本にまとめています。

電話番号や郵便番号など、「記号を全部取り除いて数字だけにしたい」場面では、この挙動がとても使いやすいです。


2. LINQ を使った“短く書ける版”

Where+ToArray で書き直す

同じことを LINQ で書くと、かなり短くなります。

using System;
using System.Linq;

public static class DigitExtractorLinq
{
    public static string ExtractDigits(string? value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return string.Empty;
        }

        return new string(value.Where(char.IsDigit).ToArray());
    }
}
C#

ここでやっていることは、さっきのループと本質的には同じです。

  • value.Where(char.IsDigit) で「数字だけ」をフィルタ
  • ToArray()char[] に変換
  • new string(...) で文字列にする

LINQ に慣れてくると、この書き方のほうが「何をしているか」が一行で伝わるので、
個人的にはかなり好きなパターンです。

動作はループ版と同じ

Console.WriteLine(DigitExtractorLinq.ExtractDigits("ID: 12345"));        // 12345
Console.WriteLine(DigitExtractorLinq.ExtractDigits("AB-2025-00123"));    // 202500123
Console.WriteLine(DigitExtractorLinq.ExtractDigits("TEL 03-1234-5678")); // 0312345678
C#

「数字だけ全部くっつける」という挙動は、ループ版と完全に同じです。


3. 正規表現で「数字の塊ごと」に抜き出す

Regex.Matches で“数字の塊”を全部取る

今までは「数字だけ全部くっつける」でしたが、
「数字の塊ごとに欲しい」こともあります。

例えば、"AB-2025-00123" から ["2025", "00123"] のように取りたい場合です。

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public static class DigitGroupExtractor
{
    public static string[] ExtractDigitGroups(string? value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return Array.Empty<string>();
        }

        var list = new List<string>();

        MatchCollection matches = Regex.Matches(value, @"\d+");

        foreach (Match m in matches)
        {
            if (m.Success)
            {
                list.Add(m.Value);
            }
        }

        return list.ToArray();
    }
}
C#

ここでのポイントは、

  • @"\d+" … 「数字が 1 文字以上続く塊」にマッチする正規表現
  • Regex.Matches … マッチしたもの全部を返す
  • m.Value … その塊の文字列

という流れです。

動作例で違いを確認する

void Dump(string label, string? value)
{
    Console.WriteLine($"[{label}]");
    foreach (var x in DigitGroupExtractor.ExtractDigitGroups(value))
    {
        Console.WriteLine($"  -> {x}");
    }
}

Dump("AB-2025-00123", "AB-2025-00123");
//  -> 2025
//  -> 00123

Dump("TEL 03-1234-5678", "TEL 03-1234-5678");
//  -> 03
//  -> 1234
//  -> 5678

Dump("No digits!", "No digits!");
// (何も出ない)
C#

「数字の塊ごとに分けて欲しい」か、「全部くっつけて欲しい」かで、
使うユーティリティを変えるイメージです。


4. 数字抽出+数値変換までやるユーティリティ

「数字だけ取りたい」ではなく「int にしたい」ことが多い

業務では、「数字だけ取りたい」の最終目的は、
だいたい「数値として扱いたい」です。

例えば、"ID: 00123" から 123(int)を取りたい、など。

そこで、「数字抽出+int 変換」までをまとめたユーティリティを作っておくと便利です。

using System;

public static class DigitParseUtil
{
    public static int? ExtractInt(string? value)
    {
        string digits = DigitExtractor.ExtractDigits(value);

        if (digits.Length == 0)
        {
            return null;
        }

        if (int.TryParse(digits, out int result))
        {
            return result;
        }

        return null;
    }
}
C#

ここでは、

  1. まず ExtractDigits で数字だけを取り出す。
  2. 何も数字がなければ null。
  3. int.TryParse で数値に変換できればその値、できなければ null。

という挙動にしています。

動作例

Console.WriteLine(DigitParseUtil.ExtractInt("ID: 00123"));        // 123
Console.WriteLine(DigitParseUtil.ExtractInt("No digits"));        // null
Console.WriteLine(DigitParseUtil.ExtractInt("999999999999999"));  // null(int の範囲外)
C#

呼び出し側は、「null ならまともな数字が取れなかった」と判断できます。


5. 実務での設計ポイント 「どの粒度で欲しいか」を最初に決める

数字抽出ユーティリティを設計するときに、最初に決めておきたいのは次の 2 点です。

1つ目は、「数字だけ全部くっつけた 1 本の文字列が欲しいのか?」
2つ目は、「数字の塊ごとに配列で欲しいのか?」

電話番号・郵便番号・ID など、「記号を全部取り除いて数字だけにしたい」なら、
ExtractDigits のような「全部くっつける」系が向いています。

ログやフリーテキストから「数字の塊を全部拾いたい」なら、
ExtractDigitGroups のような「塊ごと」系が向いています。

さらに、「最終的に数値として扱いたい」なら、
ExtractInt のように「抽出+数値変換」までを 1 つのユーティリティにしておくと、
呼び出し側のコードがかなりスッキリします。


まとめ 「数字のみ抽出ユーティリティ」は“文字列から数値情報だけを救い出すフィルタ”

数字のみ抽出は、見た目は地味ですが、
「文字列の中に埋もれた数値情報を、きれいに取り出す」ための大事なフィルタです。

押さえておきたいポイントをコンパクトにまとめると、

  • 1 文字ずつ見て char.IsDigit で拾う方法は、シンプルで分かりやすく、電話番号などに向いている。
  • LINQ を使うと、new string(value.Where(char.IsDigit).ToArray()) の一行で書ける。
  • 正規表現 \d+ を使うと、「数字の塊ごと」に配列として取り出せる。
  • 「数字だけ取りたい」のか「数字を int にしたい」のかを分けて、ユーティリティを設計すると呼び出し側が楽になる。

ここまで理解できれば、「とりあえず数字を抜いてるだけ」の段階から一歩進んで、
“文字列から数値情報だけを救い出すフィルタ”として、
業務で使える C# の数字抽出ユーティリティを、自分の手で設計・実装できるようになっていきます。

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