using System.Collections.Generic;
using System.Text.RegularExpressions;
public static void Main()
foreach (var number in testNumbers)
var phoneRecord = PhoneNumberRegionIdentifier.ExtractPhoneNumberRecord(number);
string classification = PhoneNumberRegionIdentifier.ClassifyPhoneNumber(number);
Console.WriteLine($"输入: {number}");
Console.WriteLine($"国家或区域代码: {phoneRecord.RegionCode}");
Console.WriteLine($"地区名称: {classification}");
Console.WriteLine($"完整格式: {phoneRecord.FullNumber ?? "null"}");
Console.WriteLine($"是否有效: {phoneRecord.IsValid}");
Console.WriteLine($"清爽格式: {phoneRecord.CleanNumber}");
Console.WriteLine($"区域代码(含前缀): {phoneRecord.RegionCodeWithPrefix}");
Console.WriteLine("-------------------");
public class PhoneNumberRegionIdentifier
public record PhoneNumberRecord(string FullNumber, string RegionCode, bool IsValid,string CleanNumber,string RegionCodeWithPrefix);
private static readonly Regex RegionCodeRegex = new Regex(@"^([(\uFF08]\+(?<regionCode>\d{1,3})[)\uFF09])|^([(\uFF08]00(?<regionCode>\d{1,3})[)\uFF09])|^\+(?<regionCode>\d{1,3})|^00(?<regionCode>\d{1,3})",RegexOptions.Compiled);
private static readonly Dictionary<string, (int MinLength, int MaxLength)> RegionPhoneNumberLengths = new()
public static (string RegionCode, bool IsValid) IdentifyRegionCode(string phoneNumber, string defaultRegionCode = "86")
if (string.IsNullOrWhiteSpace(phoneNumber))
return (defaultRegionCode, false);
var match = RegionCodeRegex.Match(phoneNumber);
string numberWithoutRegionCode;
regionCode = match.Groups["regionCode"].Value;
numberWithoutRegionCode = phoneNumber.Substring(match.Length).Trim();
regionCode = defaultRegionCode;
numberWithoutRegionCode = phoneNumber.Trim();
string cleanedNumber = Regex.Replace(numberWithoutRegionCode, @"[^0-9]", "");
if (string.IsNullOrEmpty(cleanedNumber))
return (regionCode, false);
if (RegionPhoneNumberLengths.TryGetValue(regionCode, out var lengthRange))
int numberLength = cleanedNumber.Length;
if (numberLength < lengthRange.MinLength || numberLength > lengthRange.MaxLength)
return (regionCode, false);
return (regionCode, false);
return (regionCode, true);
public static string ClassifyPhoneNumber(string phoneNumber, string defaultRegionCode = "86")
var (regionCode, isValid) = IdentifyRegionCode(phoneNumber, defaultRegionCode);
return "Invalid Phone Number";
case "1": return "United States/Canada";
case "7": return "Russia";
case "20": return "Egypt";
case "27": return "South Africa";
case "30": return "Greece";
case "31": return "Netherlands";
case "32": return "Belgium";
case "33": return "France";
case "34": return "Spain";
case "36": return "Hungary";
case "39": return "Italy";
case "40": return "Romania";
case "41": return "Switzerland";
case "43": return "Austria";
case "44": return "United Kingdom";
case "45": return "Denmark";
case "46": return "Sweden";
case "47": return "Norway";
case "48": return "Poland";
case "49": return "Germany";
case "51": return "Peru";
case "52": return "Mexico";
case "53": return "Cuba";
case "54": return "Argentina";
case "55": return "Brazil";
case "56": return "Chile";
case "57": return "Colombia";
case "58": return "Venezuela";
case "60": return "Malaysia";
case "61": return "Australia";
case "62": return "Indonesia";
case "63": return "Philippines";
case "64": return "New Zealand";
case "65": return "Singapore";
case "66": return "Thailand";
case "81": return "Japan";
case "82": return "South Korea";
case "84": return "Vietnam";
case "86": return "China";
case "90": return "Turkey";
case "91": return "India";
case "92": return "Pakistan";
case "93": return "Afghanistan";
case "94": return "Sri Lanka";
case "95": return "Myanmar";
case "98": return "Iran";
case "212": return "Morocco";
case "213": return "Algeria";
case "216": return "Tunisia";
case "218": return "Libya";
case "220": return "Gambia";
case "221": return "Senegal";
case "222": return "Mauritania";
case "223": return "Mali";
case "224": return "Guinea";
case "225": return "Ivory Coast";
case "226": return "Burkina Faso";
case "227": return "Niger";
case "228": return "Togo";
case "229": return "Benin";
case "230": return "Mauritius";
case "231": return "Liberia";
case "232": return "Sierra Leone";
case "233": return "Ghana";
case "234": return "Nigeria";
case "235": return "Chad";
case "236": return "Central African Republic";
case "237": return "Cameroon";
case "238": return "Cape Verde";
case "239": return "Sao Tome and Principe";
case "240": return "Equatorial Guinea";
case "241": return "Gabon";
case "242": return "Congo (Brazzaville)";
case "243": return "Congo (Kinshasa)";
case "244": return "Angola";
case "245": return "Guinea-Bissau";
case "246": return "Diego Garcia";
case "248": return "Seychelles";
case "249": return "Sudan";
case "250": return "Rwanda";
case "251": return "Ethiopia";
case "252": return "Somalia";
case "253": return "Djibouti";
case "254": return "Kenya";
case "255": return "Tanzania";
case "256": return "Uganda";
case "257": return "Burundi";
case "258": return "Mozambique";
case "260": return "Zambia";
case "261": return "Madagascar";
case "262": return "Reunion";
case "263": return "Zimbabwe";
case "264": return "Namibia";
case "265": return "Malawi";
case "266": return "Lesotho";
case "267": return "Botswana";
case "268": return "Swaziland";
case "269": return "Comoros";
case "290": return "Saint Helena";
case "291": return "Eritrea";
case "297": return "Aruba";
case "298": return "Faroe Islands";
case "299": return "Greenland";
case "852": return "Hong Kong";
case "853": return "Macau";
default: return "Unknown Region";
public static (string FullNumber, string RegionCode, bool IsValid) ExtractPhoneNumber(string phoneNumber, string defaultRegionCode = "86")
if (string.IsNullOrWhiteSpace(phoneNumber))
return (null, defaultRegionCode, false);
var match = RegionCodeRegex.Match(phoneNumber);
string numberWithoutRegionCode;
regionCode = match.Groups["regionCode"].Value;
numberWithoutRegionCode = phoneNumber.Substring(match.Length).Trim();
regionCode = defaultRegionCode;
numberWithoutRegionCode = phoneNumber.Trim();
string cleanedNumber = Regex.Replace(numberWithoutRegionCode, @"[^0-9]", "");
if (string.IsNullOrEmpty(cleanedNumber))
return (null, regionCode, false);
if (RegionPhoneNumberLengths.TryGetValue(regionCode, out var lengthRange))
int numberLength = cleanedNumber.Length;
if (numberLength < lengthRange.MinLength || numberLength > lengthRange.MaxLength)
return (null, regionCode, false);
return (null, regionCode, false);
var prefixSymbol = regionCode == "86" ? "00" : "+";
string fullNumber = $"{prefixSymbol}{regionCode}{cleanedNumber}";
return (fullNumber, regionCode, true);
public static PhoneNumberRecord ExtractPhoneNumberRecord(string phoneNumber, string defaultRegionCode = "86",string defaultRegionCodePrefix ="+")
if (string.IsNullOrWhiteSpace(phoneNumber))
return new PhoneNumberRecord(null,defaultRegionCode,false,null,null);
var match = RegionCodeRegex.Match(phoneNumber);
string numberWithoutRegionCode;
regionCode = match.Groups["regionCode"].Value;
numberWithoutRegionCode = phoneNumber.Substring(match.Length).Trim();
regionCode = defaultRegionCode;
numberWithoutRegionCode = phoneNumber.Trim();
string cleanedNumber = Regex.Replace(numberWithoutRegionCode, @"[^0-9]", "");
if (string.IsNullOrEmpty(cleanedNumber))
return new PhoneNumberRecord(null,regionCode,false,null,null);
if (RegionPhoneNumberLengths.TryGetValue(regionCode, out var lengthRange))
int numberLength = cleanedNumber.Length;
if (numberLength < lengthRange.MinLength || numberLength > lengthRange.MaxLength)
return new PhoneNumberRecord(null,regionCode,false,null,null);
return new PhoneNumberRecord(null,regionCode,false,null,null);
if (string.IsNullOrWhiteSpace(defaultRegionCodePrefix))
defaultRegionCodePrefix = "+";
var regionCodeWithPrefix = $"{defaultRegionCodePrefix}{regionCode}";
var fullNumber = $"{regionCodeWithPrefix}{cleanedNumber}";
return new PhoneNumberRecord(fullNumber,regionCode,true,cleanedNumber,regionCodeWithPrefix);