【问题标题】:Converting a normalized phone number to a user-friendly version将规范化的电话号码转换为用户友好的版本
【发布时间】:2009-01-08 20:40:15
【问题描述】:

在我的 C# 应用程序中,我使用正则表达式来验证美国电话号码的基本格式,以确保用户不只是输入虚假数据。然后,我去掉除数字之外的所有内容,所以:

(123) 456-7890 x1234

变成

12345678901234

在数据库中。然而,在我的应用程序的各个部分,我想将这个规范化的电话号码转换回

(123) 456-7890 x1234

这样做的最佳方法是什么? (顺便说一句,不用担心国际电话号码格式。)

【问题讨论】:

  • 你有把这个:(123) 456-7890 x1234 转换成这个:12345678901234 的代码吗?

标签: c# regex formatting phone-number


【解决方案1】:
String.Format("{0:(###) ###-#### x ###}", double.Parse("1234567890123"))

将导致 (123) 456-7890 x 123

【讨论】:

  • 使用 double 安全吗?在这种情况下,我会使用小数。
  • Double 有足够的数字用于此目的,并且由于没有可能导致舍入错误的小数部分,它可能会“工作”。然而它并不“感觉”正确,一般来说我会避免这种“棘手”的代码。
  • 此代码不适用于字符串中的前导 0:03 9999 9999。因此它不是国际解决方案,因为在澳大利亚我们有以 0 开头的州代码。
【解决方案2】:

使用正则表达式可以替换:

(\d{3})(\d{3})(\d{4})(\d{4})

与:

(\1) \2-\3 x\4

(虽然我不熟悉美国的电话号码,所以也许还有更多。)

【讨论】:

    【解决方案3】:

    我只会使用自定义格式字符串将数字转换回字符串:

    class Program
    {
        static void Main(string[] args)
        {
            long phoneNumber = 12345678901234;
            string phoneNumberString = String.Format("{0:(000) 000-0000 x0000}", phoneNumber);
            Console.WriteLine(phoneNumberString);
        }
    }
    

    当然,您可以将其分解为一个函数,该函数将电话号码作为一个长字符串,然后返回字符串(将格式加载或存储为方法中的常量,或适合您的情况)。

    哦,如果你有一个字符串而不是长字符串,你可以轻松地将字符串转换为长字符串,然后将其传递给格式函数。当然,如果您重复执行此操作,则此处存在性能考虑(因为您正在迭代字符串以创建长字符串,然后将其转换回字符串,而您可以只使用子字符串)。

    【讨论】:

    • 我喜欢这种方法(因为它使我的用户能够在需要时更改掩码)。但是,如果输入字符串没有扩展名,这会失败吗?
    【解决方案4】:

    如果您只支持美国数字,您可以简单地格式化数字以显示括号和 x。

    我更喜欢存储整个字符串,我会使用正则表达式对其进行解析以对其进行验证,然后将其存储在规范化的字符串中。

    为了让它接受任何国家,我会这样做:

    我会将 IDD 代码添加到所有电话号码中,然后对该国家/地区的用户隐藏它。

    所以:(123) 456-7890 x1234 将存储为 +1 (123) 456-7890 x1234

    (perl 兼容的)正则表达式类似于(完全未经测试且无法工作):

    (+\d+)?\s+(((\d{,3}))(?\s+([-.0-9]{6,})\s+((x|ext\w*) \d{,4})

    • 这是一个可选的以 + 开头的位数
    • 后跟一个或多个空格
    • 然后是括号之间最多 3 位数字的可选组
    • 然后是一个或多个空格
    • 然后是一组 6 个或更多数字、破折号或圆点
    • 然后是一个或多个空格
    • 然后是可选的 x 或以 ext(分机、分机 ...)开头的单词和一组最多 4 位数字

    我会有一个用户数据库,包括国家和地区代码,然后自动填写以防他们丢失,国家将有电话号码的默认数字分组约定(美国为 3,4)。

    • 所以如果你在美国123区,输入456.7890,会被解析为+1 (123) 4567890,你只会看到456-7890
    • 如果您在卡塔尔并输入号码 4444555 extenshn 33,则存储为 +974 4444555 x33,您会看到它为 4444555 x33

    同一国家的用户不显示国际区号,同一国家和区号的用户不显示区号。完整的数字将显示在鼠标悬停上(HTML 标签?)

    【讨论】:

      【解决方案5】:

      您必须为数据库分解它吗?如果没有,不要。如果您必须,那么您可以将不同的部分存储在不同的字段中(区域代码、前缀、订阅者编号、扩展名)。

      或者,提取数字并开始解析。如果它只有 10 位数字,那么您就知道没有扩展名。所有超过 10 的数字,将它们放在字符串中的“x”或其他内容之后。

      我在一个 C++ 应用程序中做了类似的事情,我将存储的不同联系机制编写为单个字符串,但相反,我做了与你正在做的相反的事情。我从对话框中删除了字段,并构建了格式化数字以存储为字符串。

      【讨论】:

      • 不幸的是,我知道。该应用程序是现有数据库的接口,该数据库具有有关电话号码格式的规则。相信我,如果我能避免所有这些废话,我会的。 :P
      【解决方案6】:

      这是一个可能有帮助的扩展方法:

      public static string InsertStringAtPositions(this string str, string insertStr, IEnumerable<int> positions)
      {
          if (str != null && insertStr != null && positions != null)
          {
              string newString = string.Empty;
              int previousPos = 0;
              foreach (var pos in positions)
              {
                  if (pos < str.Length)
                  {
                      newString += str.Substring(previousPos, pos - previousPos) + insertStr;
                      previousPos = pos;
                  }
              }
              if (positions.Last() < str.Length)
              {
                  return newString + str.Substring(positions.Last(), str.Length - positions.Last());
              }
              return newString;
          }
          return str;
      }
      

      用法:

      // Will convert "0399998888" to "03 9999 8888"
      number.InsertStringAtPositions(" ", new[] {2, 6});
      

      【讨论】:

        猜你喜欢
        • 2018-12-01
        • 1970-01-01
        • 2011-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多