简体   繁体   English

格式化电话号码

[英]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.我想格式化一个电话号码,电话号码的长度不固定,但它应该在 7-15 位数字之间。

I need to Format this 12345678 in Like 1234-567-8我需要在 Like 1234-567-8中格式化这个12345678

If there any Digit Increase or Decrease it should be remove by end.如果有任何数字增加或减少,它应该在最后被删除。 Means I want 4Digit-3Digit-ResrtOFDigit意味着我想要4Digit-3Digit-ResrtOFDigit

Assuming that your string will contain at least 8 characters.假设您的字符串至少包含 8 个字符。

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

str will hold str将举行

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).更不用说必须处理区号可选或不可选的情况(例如美国/NANP 和英国的本地电话)。
  • 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.幸运的是,解决方案是 只使用 Google 的LibPhoneNumber :它由 Google 积极维护,因为它在 Android 和 Google 自己的在线服务中用于格式化电话号码。

Here's a simple example of how to use libphonenumber it as a DI service:下面是一个如何将libphonenumber用作 DI 服务的简单示例:

Step 1: Copypasta:第 1 步:复制意大利面:

Copy and paste the interface IPhoneNumberService and class GoogleLpnPhoneNumberService below into your project:将下面的interface IPhoneNumberServiceclass GoogleLpnPhoneNumberService复制并粘贴到您的项目中:

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 :要使用Microsoft.Extensions.DependencyInjection注册此服务,请将其添加到您的ConfigureServices

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

Step 2: Usage examples:第 2 步:用法示例:

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: 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... Google.LibPhoneNumber NuGet package 是原始 Java libphonenumber的直接 C#/.NET 端口,它通过将 Java 惯用语携带到 C# 代码中显示其传统,例如...
      • Using GetInstance() getter-methods instead of getter properties.使用GetInstance() getter 方法而不是 getter 属性。
      • Using a non-company-specific root namespace using global::PhoneNumbers;使用using global::PhoneNumbers; . .
      • Not having exception-free TryParse methods and instead depending on consuming code to use try/catch(NumberParseException) , * grumble *没有无异常的TryParse方法,而是依赖于使用try/catch(NumberParseException)的消费代码,*抱怨*
    • ...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.谢谢你的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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