Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
L

libphonenumber-csharp

> 编程语言
Open source

Offical C# port of https://github.com/googlei18n/libphonenumber

918 stars0 likes0 views
WebsiteGitHub

About

Offical C# port of https://github.com/googlei18n/libphonenumber

C# port of Google's libphonenumber library.

The code was rewritten from the Java source mostly unchanged, please refer to the original documentation for sample code and API documentation.

The original Apache License 2.0 was preserved.

[!TIP] Try the interactive demo → — parse, format, validate, and find phone numbers in your browser. No install required; runs entirely via WebAssembly.

See this for details about the port.

Phone number metadata is updated in the Google repo approximately every two weeks. This library is automatically updated by a scheduled github action to include the latest metadata, usually within a day. See Metadata updates for how that works and how to run it manually.

See CHANGELOG.md for release history.

Installation

Run the following command to add this library to your project

dotnet add package libphonenumber-csharp

Available on NuGet as package libphonenumber-csharp.

Targets netstandard2.0, net8.0 and net10.0.

libphonenumber-csharp.extensions is an optional companion package with helpers that suit C# better than the ported Java API — PhoneNumber.TryParse and PhoneNumber.TryParseValid return a bool instead of throwing, and PhoneNumberConverter is a System.Text.Json converter for PhoneNumber.

Trimming and Native AOT

The library is annotated as trim- and AOT-compatible, and the trim/AOT analyzers run as part of its own build. All metadata — including the geocoding, carrier and time zone prefix maps — is compiled to a binary form at build time and embedded in the assembly as compressed resources, so no XML is parsed and no file is read from disk at run time. The interactive demo is a Blazor WebAssembly app that runs this library trimmed, in the browser.

Regex compilation and startup cost

Validation and formatting are driven by regexes built from the bundled metadata. There are thousands of them, and each is built the first time some caller touches that region.

Those metadata regexes are deliberately not built with RegexOptions.Compiled. Compiling one costs around 1.5 ms of IL-emit and saves roughly 0.044 µs per match, so a pattern has to be matched on the order of 30,000 times before compiling it breaks even — which metadata patterns rarely are, because a workload spread across regions matches each one comparatively few times. Measured end-to-end on net8.0 (total wall time including startup, parse + validate + format), compiling them is 34x slower for 1,000 operations across 245 regions, 3.7x slower for 100,000, and still 1.7x slower at 1,000,000. It wins only for a process concentrating very high volume on one or two regions, and then by 6–20%.

The library's own fixed regexes are a different case and are still compiled: there is a small, fixed number of them, each built once per process and hot for its whole life.

There is no per-call knob for this. If you have measured a workload where compiling the metadata patterns wins — a long-running process concentrating very high volume on one or two regions is the shape where it can — please open an issue with the numbers rather than reaching for internal types.

Debugging and symbols

Symbols are published to the NuGet.org symbol server as a .snupkg alongside each release, with Source Link wired up — enable symbol server support in your debugger to step into the library.

Examples

Parsing a phone number

csharp
using PhoneNumbers;

var phoneNumberUtil = PhoneNumberUtil.GetInstance();
var e164PhoneNumber = "+44 117 496 0123";
var nationalPhoneNumber = "2024561111";
var smsShortNumber = "83835";
var phoneNumber = phoneNumberUtil.Parse(e164PhoneNumber, null);
phoneNumber = phoneNumberUtil.Parse(nationalPhoneNumber, "US");
phoneNumber = phoneNumberUtil.Parse(smsShortNumber, "US");

Formatting a phone number

csharp
using PhoneNumbers;

var phoneNumberUtil = PhoneNumberUtil.GetInstance();
var phoneNumber = phoneNumberUtil.Parse("+14156667777", "US");
var formattedPhoneNumber = phoneNumberUtil.Format(phoneNumber, PhoneNumberFormat.INTERNATIONAL);
var formattedPhoneNumberNational = phoneNumberUtil.Format(phoneNumber, PhoneNumberFormat.NATIONAL);

Console.WriteLine(formattedPhoneNumber.ToString()); // +1 415-666-7777
Console.WriteLine(formattedPhoneNumberNational.ToString()); // (415) 666-7777

Check if a phone number is valid

csharp
using PhoneNumbers;

var phoneNumberUtil = PhoneNumberUtil.GetInstance();
var phoneNumber = phoneNumberUtil.Parse("+14156667777", "US");
var isValid = phoneNumberUtil.IsValidNumber(phoneNumber);

Console.WriteLine(isValid); // true

Get the type of a phone number

csharp
using PhoneNumbers;

var phoneNumberUtil = PhoneNumberUtil.GetInstance();
var phoneNumber = phoneNumberUtil.Parse("+14156667777", "US");
var numberType = phoneNumberUtil.GetNumberType(phoneNumber);

Console.WriteLine(numberType); // PhoneNumberType.FIXED_LINE_OR_MOBILE

See PhoneNumberType.cs for the various possible types of phone numbers

Get the region code for a phone number

csharp
using PhoneNumbers;

var phoneNumberUtil = PhoneNumberUtil.GetInstance();
var phoneNumber = phoneNumberUtil.Parse("+14156667777", null);
var regionCode = phoneNumberUtil.GetRegionCodeForNumber(phoneNumber);

Console.WriteLine(regionCode); // US

Get the location of a phone number

csharp
using PhoneNumbers;

var phoneNumberUtil = PhoneNumberUtil.GetInstance();
var geocoder = PhoneNumberOfflineGeocoder.GetInstance();
var phoneNumber = phoneNumberUtil.Parse("+12128120000", null);
var description = geocoder.GetDescriptionForNumber(phoneNumber, Locale.English);

Console.WriteLine(description); // New York, NY

The lookup is entirely offline. Detail varies by region — some yield a city, others only a state or the country name — and non-geographic or invalid numbers return the country name or an empty string. Pass a user region to omit it from the description for local numbers, or use GetDescriptionForValidNumber to skip the internal validity check.

Get the time zones for a phone number

csharp
using PhoneNumbers;

var phoneNumberUtil = PhoneNumberUtil.GetInstance();
var timeZonesMapper = PhoneNumberToTimeZonesMapper.GetInstance();
var phoneNumber = phoneNumberUtil.Parse("+12128120000", null);
var timeZones = timeZonesMapper.GetTimeZonesForNumber(phoneNumber);

Console.WriteLine(string.Join(", ", timeZones)); // America/New_York

Returns a List of IANA time zone identifiers. For numbers that span multiple time zones (e.g. a country-level lookup), the list will contain more than one entry. Returns ["Etc/Unknown"] for invalid or unrecognised numbers.

Use GetTimeZonesForGeographicalNumber instead if you have already validated the number and want to skip the internal type check.

Get the carrier name for a phone number

csharp
using PhoneNumbers;

var phoneNumberUtil = PhoneNumberUtil.GetInstance();
var carrierMapper = PhoneNumberToCarrierMapper.GetInstance();
var phoneNumber = phoneNumberUtil.Parse("+917503397672", null);
var carrierName = carrierMapper.GetNameForNumber(phoneNumber, Locale.English);

Console.WriteLine(carrierName); // Aircel

Note: Carrier data reflects the original network allocation. If the country supports mobile number portability, the number may have since moved to a different carrier. Use GetSafeDisplayName to return an empty string in those regions.

Features

  • Parsing/formatting/validating phone numbers for all countries/regions of the world.
  • GetNumberType - gets the type of the number based on the number itself; able to distinguish Fixed-line, Mobile, Toll-free, Premium Rate, Shared Cost, VoIP and Personal Numbers (whenever feasible).
  • IsNumberMatch - gets a confidence level on whether two numbers could be the same.
  • GetExampleNumber/GetExampleNumberByType - provides valid example numbers for 218 countries/regions, with the option of specifying which type of example phone number is needed.
  • IsPossibleNumber - quickly guessing whether a number is a possible phone number by using only the length information, much faster than a full validation.
  • AsYouTypeFormatter - formats phone numbers on-the-fly when users enter each digit.
  • FindNumbers - finds numbers in text input
  • PhoneNumberToCarrierMapper - looks up the carrier name originally assigned to a mobile or pager number, with locale-aware output and a safe-display mode for regions with mobile number portability.
  • PhoneNumberOfflineGeocoder - describes where a number is from, in a requested language, without a network call.
  • PhoneNumberToTimeZonesMapper - maps a number to its IANA time zone identifiers.

See PhoneNumberUtil.cs for the various methods and properties available.

Why keep libphonenumber-csharp up to date?

A lot of the functionality depends on updated metadata that is published by the google repository, see example here.

This means that if you don't keep the package up to date, methods like IsValidNumber will return false for newer numbers that rely on the updated metadata

Therefore, we recommend you keep this nuget package as up to date as possible using automated means (such as dependabot) as metadata changes published by the google repository is frequent, usually a few times a month.

For more information on metadata usage, please refer to the main repository faq

Running tests locally

bash
# Every project, every target framework.
dotnet test csharp/PhoneNumbers.slnx

# Faster, and what the pull request check runs.
dotnet test csharp/PhoneNumbers.slnx -p:TargetFrameworks=net10.0

The binary metadata the library reads at run time is generated during the build, so a plain dotnet build is all that is needed first — there is no separate generation step. See CONTRIBUTING.md for the build settings that will fail CI if missed.

Metadata updates

The create_new_release_on_new_metadata_update workflow runs daily at 08:00 UTC and drives lib/github-actions-metadata-update.sh. When the latest google/libphonenumber release is newer than the published NuGet package, it copies the upstream resources/ (less upstream's metadata/ csv tables, which nothing here reads), regenerates resources/locale/country_names.txt, adds a CHANGELOG.md entry for the release, then commits, pushes to a metadata-update/* branch and opens a PR against main with auto-merge deliberately left off. The push and PR authenticate as the dedicated libphonenumber-csharp-bot account (via the BOT_ACCESS_TOKEN secret) rather than the default GITHUB_TOKEN, since GitHub requires a maintainer to manually approve workflow runs on PRs opened with GITHUB_TOKEN.

A maintainer reviews and merges that PR, which is how a metadata release ships. If nobody has merged it by the next daily run, that run enables auto-merge so the release still goes out — a sync is never left stalled because nobody was around. Once it merges, [finalize_metadata_release](https://github.com/twcclegg/libphonenumber-csharp/actions/workflows/finalize

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

C#csharpe164java-sourcelibphonenumber

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言