はじめに 「電話番号検証」は“ぐちゃっとした入力を、安全な数字列に整える”仕事
電話番号入力って、郵便番号以上に“ゆらぎ”が激しいです。
03-1234-56780901234567803−1234−5678(+81) 90-1234-5678
人によって書き方がバラバラなのに、
システム側は「ちゃんとした電話番号として扱いたい」「検索や帳票では統一した形で出したい」。
ここで本当に欲しいのは、
「人間のゆらぎを受け止めつつ、内部では“数字だけの電話番号”として扱えるユーティリティ」
です。
ここでは、初心者向けに、
- 電話番号検証の考え方(“完全正解”ではなく“現実解”を目指す)
- 数字だけに正規化するユーティリティ
- 桁数や先頭の番号で“それっぽいか”をチェックする
- ハイフン付き表示用に再フォーマットする
までを、例題付きでかみ砕いて説明していきます。
電話番号検証の方針を決める 「何をOKとするか?」
日本の電話番号をざっくり整理する
厳密にやろうとすると総務省レベルの話になるので、
ここでは“実務でよく使う範囲”に絞ります。
ざっくり、こんな感じです。
- 固定電話(例)
03-1234-5678、045-123-4567など - 携帯電話(例)
090-1234-5678、080-xxxx-xxxx - フリーダイヤルなど(例)
0120-xxx-xxx
実務でよくやるのは、
「数字だけにして、10桁 or 11桁ならOKとみなす(日本国内想定)」
という現実解です。
- 固定電話 → だいたい 10 桁
- 携帯電話 → だいたい 11 桁
ここをベースにして、細かいルール(先頭が 0 かどうか、など)を足していきます。
ステップ1:数字だけに正規化する
まずは「数字以外は全部ノイズ」とみなす
どんな書き方をされていても、
最終的には「数字だけの電話番号」にしたいので、
最初の一歩は「数字だけを抜き出す」ことです。
using System;
using System.Linq;
public static class PhoneNumberNormalizer
{
public static string ExtractDigits(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
// 全角数字も考えるなら、先に全角→半角変換を挟むのもアリ
return new string(value.Where(char.IsDigit).ToArray());
}
}
C#やっていることはシンプルです。
- null や空白だけなら空文字を返す
- 1文字ずつ見て、
char.IsDigitが true のものだけを拾う new string(...ToArray())で数字だけの文字列にする
動作例でイメージを固める
Console.WriteLine(PhoneNumberNormalizer.ExtractDigits("03-1234-5678")); // 0312345678
Console.WriteLine(PhoneNumberNormalizer.ExtractDigits("090-1234-5678")); // 09012345678
Console.WriteLine(PhoneNumberNormalizer.ExtractDigits("(+81) 90-1234-5678")); // 819012345678
Console.WriteLine(PhoneNumberNormalizer.ExtractDigits("abc")); // 空文字
Console.WriteLine(PhoneNumberNormalizer.ExtractDigits(null)); // 空文字
C#ここで重要なのは、
「数字以外は全部捨てる」
という割り切りです。
このあと、「桁数」や「先頭の数字」で“それっぽいか”を判定していきます。
ステップ2:「日本の電話番号としてそれっぽいか」を判定する
10桁 or 11桁かどうかを見る
まずは、数字だけにした結果が「10桁 or 11桁かどうか」を見ます。
public static class PhoneNumberValidator
{
public static bool IsLikelyJapanesePhoneNumber(string? value)
{
string digits = PhoneNumberNormalizer.ExtractDigits(value);
// 10桁 or 11桁のみ許可
if (digits.Length == 10 || digits.Length == 11)
{
// 先頭が 0 でないものは日本の電話番号としては怪しいので弾く
return digits[0] == '0';
}
return false;
}
}
C#ここでは、
- 数字だけにして 10 桁 or 11 桁なら候補
- さらに「先頭が 0 かどうか」を見る(日本の電話番号はだいたい 0 から始まる)
という“ざっくりした現実解”を採用しています。
動作例
Console.WriteLine(PhoneNumberValidator.IsLikelyJapanesePhoneNumber("03-1234-5678")); // true(10桁、先頭0)
Console.WriteLine(PhoneNumberValidator.IsLikelyJapanesePhoneNumber("090-1234-5678")); // true(11桁、先頭0)
Console.WriteLine(PhoneNumberValidator.IsLikelyJapanesePhoneNumber("123-456-7890")); // false(先頭1)
Console.WriteLine(PhoneNumberValidator.IsLikelyJapanesePhoneNumber("090-1234-567")); // false(桁数不足)
Console.WriteLine(PhoneNumberValidator.IsLikelyJapanesePhoneNumber("abc")); // false
C#この時点で、「明らかに電話番号ではないもの」はかなり弾けます。
ステップ3:正規化+検証を一度に行うユーティリティ
Try パターンで「正規化済みの数字列」を返す
実務では、
「入力が妥当なら“正規化済みの数字列”を返してほしい」
ことが多いので、TryParse 風のメソッドにしておくと使いやすくなります。
public static class PhoneNumberUtil
{
public static bool TryNormalizeJapanesePhoneNumber(string? value, out string normalizedDigits)
{
normalizedDigits = string.Empty;
string digits = PhoneNumberNormalizer.ExtractDigits(value);
// 10桁 or 11桁のみ許可
if (digits.Length != 10 && digits.Length != 11)
{
return false;
}
// 先頭が 0 でないものは弾く
if (digits[0] != '0')
{
return false;
}
normalizedDigits = digits;
return true;
}
}
C#動作例
void Test(string? input)
{
if (PhoneNumberUtil.TryNormalizeJapanesePhoneNumber(input, out var normalized))
{
Console.WriteLine($"{input} -> OK: {normalized}");
}
else
{
Console.WriteLine($"{input} -> NG");
}
}
Test("03-1234-5678"); // OK: 0312345678
Test("090-1234-5678"); // OK: 09012345678
Test("03−1234−5678"); // OK: 0312345678(※全角対応を足せばこうできる)
Test("123-456-7890"); // NG
Test("090-1234-567"); // NG
C#ここまでで、
- 「妥当な電話番号かどうか」を判定しつつ
- 「内部で使いやすい“数字だけの電話番号”」を取り出す
というユーティリティができました。
全角数字・全角ハイフン・国番号をどう扱うか
全角数字・全角ハイフンを半角に寄せる
郵便番号のときと同じように、
全角数字・全角ハイフンを半角に寄せてから ExtractDigits する、という設計もよく使います。
public static class ZenkakuToHankakuUtil
{
public static string ToHalfWidthDigitsAndHyphen(string value)
{
if (string.IsNullOrEmpty(value))
{
return value;
}
var chars = value.ToCharArray();
for (int i = 0; i < chars.Length; i++)
{
char c = chars[i];
if (c >= '0' && c <= '9')
{
chars[i] = (char)('0' + (c - '0'));
}
else if (c == 'ー' || c == '−' || c == '―' || c == '-')
{
chars[i] = '-';
}
}
return new string(chars);
}
}
C#これを ExtractDigits の前に挟めば、"03−1234−5678" のような入力もきれいに扱えます。
国番号付き(+81)の扱い
(+81) 90-1234-5678 のような国番号付きの電話番号をどう扱うかは、要件次第です。
- 「国内向けシステムなので、国番号付きは想定しない」
→ そのまま弾いてしまってもよい - 「国番号付きも受け取りたいが、内部では国内形式にしたい」
→81から始まる場合に0に変換するなどのロジックを足す
例えば、819012345678(+81 90 1234 5678)を 09012345678 に寄せるなら、
「先頭が 81 で、続く桁数がそれっぽい場合に 0 を付け直す」といった処理を追加します。
これは少し込み入るので、「必要になったら足す」くらいのスタンスでOKです。
ステップ4:表示用に「ハイフン付き」に整形する
内部は数字だけ、表示はハイフン付き
内部では「数字だけ」にしておくと扱いやすいですが、
画面や帳票では「03-1234-5678」のようにハイフン付きで出したいことが多いです。
ここでは、ざっくりとした整形ルールを決めてしまいます。
- 10桁 → 固定電話として
XX-XXXX-XXXX形式にする - 11桁 → 携帯電話として
XXX-XXXX-XXXX形式にする
public static class PhoneNumberFormatter
{
public static string FormatWithHyphen(string digits)
{
if (digits is null)
{
return string.Empty;
}
if (digits.Length == 10)
{
// 固定電話っぽい: 2-4-4 に切る(03-1234-5678 など)
return $"{digits.Substring(0, 2)}-{digits.Substring(2, 4)}-{digits.Substring(6, 4)}";
}
if (digits.Length == 11)
{
// 携帯っぽい: 3-4-4 に切る(090-1234-5678 など)
return $"{digits.Substring(0, 3)}-{digits.Substring(3, 4)}-{digits.Substring(7, 4)}";
}
// それ以外はそのまま返す(想定外)
return digits;
}
}
C#動作例
Console.WriteLine(PhoneNumberFormatter.FormatWithHyphen("0312345678")); // 03-1234-5678
Console.WriteLine(PhoneNumberFormatter.FormatWithHyphen("09012345678")); // 090-1234-5678
Console.WriteLine(PhoneNumberFormatter.FormatWithHyphen("123")); // 123(想定外なのでそのまま)
C#実際には「市外局番の長さ」によって切り方を変えることもできますが、
まずは「2-4-4」「3-4-4」のようなシンプルルールから始めるのが現実的です。
設計のポイント 「検証」「正規化」「表示」を分ける
電話番号ユーティリティを設計するときに大事なのは、
役割をきちんと分けることです。
- 「数字だけにする」 →
ExtractDigits - 「日本の電話番号としてそれっぽいか判定」 →
IsLikelyJapanesePhoneNumber/TryNormalizeJapanesePhoneNumber - 「表示用にハイフン付きに整形」 →
FormatWithHyphen
こう分けておくと、
- 入力チェックでは
TryNormalizeJapanesePhoneNumberを使う - DB には
normalizedDigits(数字だけ)を保存する - 画面表示では
FormatWithHyphenで見やすくする
という流れが自然に組めます。
「どこまでゆらぎを許すか」「国番号をどう扱うか」などは、
このユーティリティの中に“ルールとして埋め込む”イメージです。
まとめ 「電話番号検証ユーティリティ」は“人間のバラバラ入力を、機械に優しい形にそろえるフィルタ”
電話番号検証は、「正規表現で形だけ見る」だけでは足りません。
実務で本当に効いてくるのは、
- 数字だけに正規化してから考える
- 桁数(10 or 11)と先頭の数字(0)で“日本の電話番号っぽさ”を判定する
- 全角数字・全角ハイフンも現実的に扱う
- 内部は数字だけ、表示はハイフン付きに整形する
- 「検証」「正規化」「表示」の役割を分けてユーティリティ化する
というあたりです。
ここまで押さえれば、「なんとなく電話番号っぽいか見ている」段階から一歩進んで、
“人間のバラバラな入力を、機械に優しい形にそろえる”
業務・実務で本当に使える C# の電話番号検証ユーティリティを、自分の手で設計・実装できるようになっていきます。
