-
Notifications
You must be signed in to change notification settings - Fork 1
/
PhoneNumber.cs
157 lines (133 loc) · 5.05 KB
/
PhoneNumber.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System.Text;
namespace DotStd
{
/// <summary>
/// Manage string phone numbers . encode/decode formatting.
/// Similar to Google phone number parser. PhoneNumbers. libphonenumber-csharp
/// max size = 15 digits + + sign = 16 digits.
/// https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers
/// https://www.twilio.com/blog/validating-phone-numbers-effectively-with-c-and-the-net-frameworks
/// https://www.itu.int/ITU-D/treg/Events/Seminars/2010/Ghana10/pdf/Session2.pdf
/// https://www.twilio.com/docs/glossary/what-e164
/// </summary>
public class PhoneNumber
{
public const int kCodeUSA = 1; // CallingCode
public const ulong kMax = 10000000000ul; // 10 to 14 digits theoretically.
public const ulong kMin = 999999ul; // never less than
public int CountryCode { get; set; } = kCodeUSA; // We get the country part of the Phone number. 1 = USA. NOT the same as CountryId. AKA CallingCode
public ulong NationalNumber { get; set; } // Get number without country code. (NOT in PhoneNumberFormat.E164 format)
public string? Extension { get; set; } // optional extension.
public bool IsValidPhone
{
get
{
// can i use this as a valid phone number?
if (CountryCode <= 0)
return false;
if (NationalNumber == 0 || NationalNumber <= kMin || NationalNumber >= kMax)
return false;
return true;
}
}
public PhoneNumber()
{
}
public PhoneNumber(ulong nationalNumber, int countryCode = kCodeUSA, string? extension = null)
{
CountryCode = countryCode;
NationalNumber = nationalNumber;
Extension = extension;
}
const string _seps = " ()-."; // only valid separators.
public bool Parse(string? phone, bool isOptional = false, int countryCodeDef = kCodeUSA)
{
// Must have 10 or more digits.
// isOptional = empty string is ok.
// RETURN: true = ok.
// EX: formats that are valid.
// ""
CountryCode = countryCodeDef;
NationalNumber = 0;
Extension = null;
if (string.IsNullOrWhiteSpace(phone))
{
return isOptional;
}
phone = phone.Trim();
int i = 0;
bool isCC = false;
if (phone[0] == '+') // starts with a country code.
{
isCC = true;
i = 1;
}
for (; i < phone.Length; i++)
{
char ch = phone[i];
if (char.IsDigit(ch))
{
NationalNumber *= 10;
NationalNumber += (ulong)(ch - '0');
if (NationalNumber >= kMax)
return false;
continue;
}
if (ch == '+') // never valid to have another country code.
return false;
if (ch == 'x' || ch == ',') // extension ?
{
if (phone.Length <= i + 1)
return false;
Extension = phone.Substring(i + 1);
break;
}
if (_seps.IndexOf(ch) < 0) // valid separator chars only.
return false;
if (isCC) // done with country code.
{
CountryCode = (int)NationalNumber;
NationalNumber = 0;
if (CountryCode == 0)
return false;
isCC = false;
}
}
if (isCC) // must not end with the country code !
return false;
return IsValidPhone;
}
public string GetUS()
{
// format 10 digit string for US style display. US format = "123-456-7890"
// No country code prefix.
ulong v0 = (this.NationalNumber / 10000000ul) % 1000;
ulong v1 = (this.NationalNumber / 10000ul) % 1000;
ulong v2 = (this.NationalNumber) % 10000;
return string.Format("{0:D3}-{1:D3}-{2:D4}", v0, v1, v2);
}
public string GetE164(bool fancy = true)
{
// get default string format.
// Get number in E164 string format. ex. "+1 617-346-8556"
string s;
if (this.CountryCode == kCodeUSA && fancy)
{
s = "+1 " + GetUS();
}
else
{
s = string.Format("+{0} {1:D10}", this.CountryCode, this.NationalNumber);
}
if (!string.IsNullOrEmpty(Extension))
{
s += "x" + Extension;
}
return s;
}
public override string ToString()
{
return GetE164(true);
}
}
}