繁体   English   中英

格式化电话号码

[英]Format a phone Number

我想格式化一个电话号码,电话号码的长度不固定,但它应该在 7-15 位数字之间。

我需要在 Like 1234-567-8中格式化这个12345678

如果有任何数字增加或减少,它应该在最后被删除。 意味着我想要4Digit-3Digit-ResrtOFDigit

假设您的字符串至少包含 8 个字符。

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

str将举行

1234-567-81213123
  • 必读程序员相信电话号码的谎言
  • 处理电话号码格式不是你应该在自己的代码中做的事情(就像日期/时间和密码学一样),因为有很多格式规则需要考虑:
    • 世界上几乎每个国家都有自己的格式,这就需要维护每个国家的格式数据库。 每个国家也可以有验证规则来限制哪些数字可以出现在某些地方。
    • 更不用说必须处理区号可选或不可选的情况(例如美国/NANP 和英国的本地电话)。
  • 实施所有这些规则,即使对于单个国家/地区,也是一项艰巨的任务,并且只要国家/地区的数字计划发生变化(并且它们一直在变化),您就需要不断更新它。
  • 幸运的是,解决方案是 只使用 Google 的LibPhoneNumber :它由 Google 积极维护,因为它在 Android 和 Google 自己的在线服务中用于格式化电话号码。

下面是一个如何将libphonenumber用作 DI 服务的简单示例:

第 1 步:复制意大利面:

将下面的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;
        }
    }
}

要使用Microsoft.Extensions.DependencyInjection注册此服务,请将其添加到您的ConfigureServices

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

第 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:

在此处输入图像描述

  • 一些注意事项:*

    • Google.LibPhoneNumber NuGet package 是原始 Java libphonenumber的直接 C#/.NET 端口,它通过将 Java 惯用语携带到 C# 代码中显示其传统,例如...
      • 使用GetInstance() getter 方法而不是 getter 属性。
      • 使用using global::PhoneNumbers; .
      • 没有无异常的TryParse方法,而是依赖于使用try/catch(NumberParseException)的消费代码,*抱怨*
    • ……不过这些都只是表面上的小事,你就忍着吧

我得到了解决方案:

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"));
}

谢谢你的帮助。

暂无
暂无

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

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