简体   繁体   中英

Format a phone Number

I want to Format a phone Number the length of Phone Number is Not Fix but it should between 7-15 Digit.

I need to Format this 12345678 in Like 1234-567-8

If there any Digit Increase or Decrease it should be remove by end. Means I want 4Digit-3Digit-ResrtOFDigit

Assuming that your string will contain at least 8 characters.

string str = "123456781213123";
if (str.Length > 7)
    str = str.Substring(0, 4) + "-" + str.Substring(4, 3) + "-" + str.Substring(7);

str will hold

1234-567-81213123
  • Obligatory required reading : Falsehoods Programmers Believe About Phone Numbers
  • Handling phone-number formatting is not something you should do in your own code (just like date/times and cryptography), because there's a lot of formatting rules to consider:
    • Almost every country in the world has its own format, which requires maintaining database of formats for each country. Each country can also have validation rules that restrict which digits can appear in certain places.
    • Not to mention having to handle cases where the area-code is optional or not (eg local calls in the US/NANP and UK).
  • Implementing all those rules, even for a single country, is a Herculean task, and you will need to constantly keep it updated whenever countries' number-plans change (and they do change, all the time).
  • Fortunately, the solution is to just use Google's LibPhoneNumber : which is actively maintained by Google because it's used in Android and Google's own online services to format phone numbers.

Here's a simple example of how to use libphonenumber it as a DI service:

Step 1: Copypasta:

Copy and paste the interface IPhoneNumberService and class GoogleLpnPhoneNumberService below into your project:

using global::PhoneNumbers;

public interface IPhoneNumberService
{
    /// <summary>Returns <see langword="null"/> when <paramref name="input"/> could not be umambiguously parsed as a valid phone number.</summary>
    /// <param name="defaultRegion">This parameter must be the ISO 3166 alpha-2 code for the default region to assume the input phone number belongs to when it does not contain a country dialing code - If <paramref name="input"/> contains a country dialing code then this parameter is ignored. Must not be null.</param>
    /// <exception cref="ArgumentException">Thrown when <paramref name="defaultRegion"/> is null or otherwise is not a valid region code.</exception>
    ( String input, String national, String e164, String? region, String? geoDesc )? ParseAndFormatPhoneNumber( String? input, String defaultRegion = "US" );
    
    #region Convenience methods // Requires C# 8.0 or higher. For .NET Framework move this code to extension methods.
    
    IReadOnlySet<String> SupportedRegions { get; }
    
    /// <summary>Convenience method.</summary>
    public Boolean TryFormatUSPhoneNumber( String? input, [NotNullWhen(true)] out String? nationalFormat, [NotNullWhen(true)] out String? e164 )
    {
        return this.TryFormatPhoneNumber( defaultRegion: "US", input: input, nationalFormat: out nationalFormat, e164: out e164 );
    }
    
    /// <summary>
    /// Convenience method.<br />
    /// Unlike <see cref="ParseAndFormatPhoneNumber"/> this method does not throw <see cref="ArgumentException"/> when <paramref name="defaultRegion"/> is invalid: this method simply returns <see langword="false"/>.
    /// </summary>
    public Boolean TryFormatPhoneNumber( String defaultRegion, String? input, [NotNullWhen(true)] out String? nationalFormat, [NotNullWhen(true)] out String? e164 )
    {
        // Validate `defaultRegion` first and return-early so `ParseAndFormatPhoneNumber` won't throw.
        if( String.IsNullOrWhiteSpace( defaultRegion ) || !this.SupportedRegions.Contains( defaultRegion ) )
        {
            nationalFormat = null;
            e164           = null;
            return false;
        }
        
        ( String input, String national, String e164, String? region, String? geoDesc )? result = this.ParseAndFormatPhoneNumber( input: input, defaultRegion: defaultRegion );
        if( result.HasValue )
        {
            nationalFormat = result.Value.national;
            e164           = result.Value.e164;
            return true;
        }
        else
        {
            nationalFormat = null;
            e164           = null;
            return false;
        }
    }
    
    #endregion
}

/// <summary>Implements <see cref="IPhoneNumberService"/> using Google's LibPhoneNumber.</summary>
/// <remarks>This service class is a singleton.</remarks>
public sealed class GoogleLpnPhoneNumberService : IPhoneNumberService
{
    public static GoogleLpnPhoneNumberService Instance { get; } = new GoogleLpnPhoneNumberService();
    
    private static readonly PhoneNumberUtil            _phoneUtil = PhoneNumberUtil.GetInstance();
    private static readonly PhoneNumberOfflineGeocoder _geo       = PhoneNumberOfflineGeocoder.GetInstance();
    
    //

    private GoogleLpnPhoneNumberService()
    {
    }
    
    public IReadOnlySet<String> SupportedRegions => _phoneUtil.GetSupportedRegions(); // <-- Careful, this is a mutable HashSet - also, it uses Default (case-sensitive) String comparisons instead of case-insensitive. Grumble.
    
    public ( String input, String national, String e164, String? region, String? geoDesc )? ParseAndFormatPhoneNumber( String? input, String defaultRegion = "US" )
    {
        if( defaultRegion is null ) throw new ArgumentNullException( nameof(defaultRegion) );
        
        if( !_phoneUtil.GetSupportedRegions().Contains( defaultRegion ) )
        {
            String msg = "The supplied region code \"" + defaultRegion + "\" is not supported by libphonenumber.";
            throw new ArgumentException( message: msg, paramName: nameof(defaultRegion) );
        }
        
        //
        
        if( String.IsNullOrWhiteSpace( input ) ) return null;
        
        try
        {
            PhoneNumber parsedPhoneNumber = _phoneUtil.Parse( numberToParse: input, defaultRegion: defaultRegion );
            // Annoyingly, the documentation doesn't say exactly what the value of `defaultRegion` should be (should it be an ITU calling code or an ISO 2-character country code?) but I find "US" works as a sensible default for North American projects, ofc.

            if( !_phoneUtil.IsValidNumber( parsedPhoneNumber ) ) return null;
            
            // Re-set the number after reformatting it:
            // Formats (see https://javadoc.io/doc/com.googlecode.libphonenumber/libphonenumber/8.10.10 )
            // International: E.123, but using local separators (if applicable). "+41 44 668 1800" (Switzerland)
            // National     : E.123, but using local separators (if applicable). "044 668 1800"
            // E164         : Same as International, but without formatting.     "+41446681800"
            // RFC3966      : Same as International, but using hyphens instead of whitespace and prepends "tel:". "tel:+41-44-668-1800"

            String intl = _phoneUtil.Format( parsedPhoneNumber, PhoneNumberFormat.INTERNATIONAL );
            String natl = _phoneUtil.Format( parsedPhoneNumber, PhoneNumberFormat.NATIONAL      );
            String e164 = _phoneUtil.Format( parsedPhoneNumber, PhoneNumberFormat.E164          );

            String? actualRegion   = _phoneUtil.GetRegionCodeForNumber( parsedPhoneNumber );
            String? geoDescription = _geo.GetDescriptionForNumber( parsedPhoneNumber, languageCode: Locale.English );
            
            return ( input, national: natl, e164, actualRegion, geoDesc: geoDescription );
        }
        catch( NumberParseException )
        {
            return null;
        }
    }
}

To register this service with Microsoft.Extensions.DependencyInjection , add this to your ConfigureServices :

public static void ConfigureServices( IServiceCollection services )
{
    _ = services.AddSingleton<IPhoneNumberService>( implementationInstance: GoogleLpnPhoneNumberService.Instance );
}

Step 2: Usage examples:

public static void Main()
{
    IPhoneNumberService svc = GoogleLpnPhoneNumberService.Instance;
    
    svc.SupportedRegions.Dump();
    
    ExampleTryFormatPhoneNumber( svc, "425-222-1234"   , defaultRegion: "US" );
    ExampleTryFormatPhoneNumber( svc, "0370 010 0222"  , defaultRegion: "GB" );
    ExampleTryFormatPhoneNumber( svc, "+44370 010 0222", defaultRegion: "US" );
    
    ExampleParseAndFormatPhoneNumber( svc, "425-222-1234", defaultRegion: "US" );
    ExampleParseAndFormatPhoneNumber( svc, "+44370 010 0222", defaultRegion: "US" );
}

public static void ExampleTryFormatPhoneNumber( IPhoneNumberService svc, String input, String defaultRegion )
{
    if( svc.TryFormatPhoneNumber( defaultRegion: defaultRegion, input: input, nationalFormat: out String? natlFmt, e164: out String? e164 ) )
    {
        ( new { Input = input, NationalFormat = natlFmt, E164 = e164 } ).Dump( "Parsed OK!" );
    }
    else
    {
        ( new { Input = input, NationalFormat = (String?)null, E164 = (String?)null } ).Dump( "Failed to parse." );
    }
}

public static void ExampleParseAndFormatPhoneNumber( IPhoneNumberService svc, String input, String defaultRegion )
{
    ( String input, String national, String e164, String? region, String? geoDesc )? result = svc.ParseAndFormatPhoneNumber( input: input, defaultRegion: defaultRegion );
    
    if( result.HasValue )
    {
        ( new { Input = input, NationalFormat = result.Value.national, E164 = result.Value.e164, Region = result.Value.region, GeoDesc = result.Value.geoDesc } ).Dump( "Failed to parse." );
    }
    else
    {
        ( new { Input = input, NationalFormat = (String?)null, E164 = (String?)null, Region = (String?)null, GeoDesc = (String?)null } ).Dump( "Failed to parse." );
    }
}

Output:

在此处输入图像描述

  • Some caveats: *

    • The Google.LibPhoneNumber NuGet package is a straightforward C#/.NET port of the original Java libphonenumber , and it shows its heritage by-way of carrying Java idioms over into C# code, such as...
      • Using GetInstance() getter-methods instead of getter properties.
      • Using a non-company-specific root namespace using global::PhoneNumbers; .
      • Not having exception-free TryParse methods and instead depending on consuming code to use try/catch(NumberParseException) , * grumble *
    • ...but these is only a minor, superficial things, so just grin and bear it .

I got the solution:

private static string FormatePhoneNumber(string phoneNumber_)
{
    return Regex.Replace(phoneNumber_, @"(\d{4})(\d{3})(\d{" + (phoneNumber_.Length - 7).ToString() + "})", "$1-$2" + ((phoneNumber_.Length - 7) == 0 ? "" : "-$3"));
}

Thanks for your help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM