C
C#13mo ago
Mekasu0124

✅ Formatting A Phone Number

I'm trying to create a function that will format a universal phone number. What I mean is if the user saves an australian phone number, then when the program goes to display that phone number it will format it appropriately, the same for other countries and american numbers too. I asked ChatGPT and it gave me
using System;
using System.Text.RegularExpressions;

class PhoneNumberFormatter
{
public static string FormatUniversalPhoneNumber(string phoneNumber)
{
// Remove non-numeric characters from the input
string cleanedNumber = Regex.Replace(phoneNumber, "[^0-9]", "");

// Check if the number has a country code and format accordingly
if (cleanedNumber.Length > 10)
{
return $"+{cleanedNumber.Substring(0, cleanedNumber.Length - 10)} " +
$"{cleanedNumber.Substring(cleanedNumber.Length - 10, 3)}-" +
$"{cleanedNumber.Substring(cleanedNumber.Length - 7, 3)}-" +
$"{cleanedNumber.Substring(cleanedNumber.Length - 4, 4)}";
}
else if (cleanedNumber.Length == 10)
{
return $"{cleanedNumber.Substring(0, 3)}-{cleanedNumber.Substring(3, 3)}-" +
$"{cleanedNumber.Substring(6, 4)}";
}
else
{
// If the number doesn't follow the standard length, return the cleaned number as is
return cleanedNumber;
}
}

static void Main()
{
string phoneNumber = "+1 (555) 123-4567";
string formattedNumber = FormatUniversalPhoneNumber(phoneNumber);
Console.WriteLine($"Formatted number: {formattedNumber}");
}
}
using System;
using System.Text.RegularExpressions;

class PhoneNumberFormatter
{
public static string FormatUniversalPhoneNumber(string phoneNumber)
{
// Remove non-numeric characters from the input
string cleanedNumber = Regex.Replace(phoneNumber, "[^0-9]", "");

// Check if the number has a country code and format accordingly
if (cleanedNumber.Length > 10)
{
return $"+{cleanedNumber.Substring(0, cleanedNumber.Length - 10)} " +
$"{cleanedNumber.Substring(cleanedNumber.Length - 10, 3)}-" +
$"{cleanedNumber.Substring(cleanedNumber.Length - 7, 3)}-" +
$"{cleanedNumber.Substring(cleanedNumber.Length - 4, 4)}";
}
else if (cleanedNumber.Length == 10)
{
return $"{cleanedNumber.Substring(0, 3)}-{cleanedNumber.Substring(3, 3)}-" +
$"{cleanedNumber.Substring(6, 4)}";
}
else
{
// If the number doesn't follow the standard length, return the cleaned number as is
return cleanedNumber;
}
}

static void Main()
{
string phoneNumber = "+1 (555) 123-4567";
string formattedNumber = FormatUniversalPhoneNumber(phoneNumber);
Console.WriteLine($"Formatted number: {formattedNumber}");
}
}
this code, but I'm not sure if it's what I'm looking for. Any tips? Thanks
50 Replies
Jimmacle
Jimmacle13mo ago
i personally use a C# port of google's libphonenumber for this kind of thing
Mekasu0124
Mekasu0124OP13mo ago
ok. illl have to do some messing around with that to figure out how to use it
Jimmacle
Jimmacle13mo ago
it might be overkill for your application, but i also validate phone numbers (as much as possible without actually calling them) and there's no way i'm maintaining that myself when
Mekasu0124
Mekasu0124OP13mo ago
well it may be a bit overkill. I was just looking for a way to format the numbers when displayed. I'm building a phone book application. The home screen shows all the user's stored contacts and I'm making a helper function to format the phone numbers as they're pulled from the database before being displayed. So like if they stored US phone numbers, it would format to +1 (123) 456-7890. If they stored an australian phone number then it would format and display like +61 (02) 123-4567 and same for like a British number +44 20 7123 4567 so basically no matter what the prefix is for the phone number, it would take that prefix, determine the necessary format for that countries phone number, and then format it appropriately. As per validation, that will happen on another screen before storing the number in the database. I need that too so that the user can only store valid phone numbers
Mayor McCheese
Mayor McCheese13mo ago
phone numbers, email addresses, street addresses, etc, they all suck at the global scale.
Mekasu0124
Mekasu0124OP13mo ago
this library is actually pretty neat and does what I need it to, however, I just may need a bit of help getting to automatically determine how to format. So like an example
string swissNumberStr = "044 668 18 00";
PhoneNumber swissNumberProto = phoneUtil.Parse(swissNumberStr, "CH");
Console.WriteLine(phoneUtil.Format(swissNumberProto, PhoneNumberFormat.INTERNATIONAL));
Console.WriteLine(phoneUtil.Format(swissNumberProto, PhoneNumberFormat.NATIONAL));
Console.WriteLine(phoneUtil.Format(swissNumberProto, PhoneNumberFormat.E164));
string swissNumberStr = "044 668 18 00";
PhoneNumber swissNumberProto = phoneUtil.Parse(swissNumberStr, "CH");
Console.WriteLine(phoneUtil.Format(swissNumberProto, PhoneNumberFormat.INTERNATIONAL));
Console.WriteLine(phoneUtil.Format(swissNumberProto, PhoneNumberFormat.NATIONAL));
Console.WriteLine(phoneUtil.Format(swissNumberProto, PhoneNumberFormat.E164));
with this method, I would have to manually insert "CH" and INTERNATIONAL, NATIONAL, or E164 for formatting the number. Is there a way I can have this library, or create a helper function to, determine the phone numbers originality whether the user enters the numbers prefix +41 or not? like in that example, the +41 doesn't exist, but they used "CH" to get the origin of the number
Mekasu0124
Mekasu0124OP13mo ago
No description
Mekasu0124
Mekasu0124OP13mo ago
so it used the "CH" to determine the numbers prefix. How could I get the program to do that automatically. Let's say I entered a US phone number (123) 456-7890. How could I get the function to recognize that it needs to be done like phoneUtil.Format(phoneNumber, "US") without having to manually put in the "US" part?
Mayor McCheese
Mayor McCheese13mo ago
I mean, this is why folks put a drop down on phone number entry for country you could have a dictionary, if I'm reading what you're asking correctly
Mekasu0124
Mekasu0124OP13mo ago
I could do a drop down. That's not a bad idea, but then I would have to look up and manually type out every countries prefix
MODiX
MODiX13mo ago
Mayor McCheese
REPL Result: Success
var dictionary = new Dictionary<string, string>();
dictionary.Add("ch", "+41");
dictionary.Add("MS", "+##");

Console.WriteLine(dictionary["ch"]);
var dictionary = new Dictionary<string, string>();
dictionary.Add("ch", "+41");
dictionary.Add("MS", "+##");

Console.WriteLine(dictionary["ch"]);
Console Output
+41
+41
Compile: 624.913ms | Execution: 75.970ms | React with ❌ to remove this embed.
Mekasu0124
Mekasu0124OP13mo ago
that's not a bad idea honestly
Mayor McCheese
Mayor McCheese13mo ago
you can json serialize a dictionary alternatively you can use "smart enums"
Mekasu0124
Mekasu0124OP13mo ago
the only downfall to doing the dictionary is if the user doesn't enter a prefix, but I could always make that a required selection from a drop down. Just finding a library that contains all the countries prefixes would be beneficial to that dictionary
Mayor McCheese
Mayor McCheese13mo ago
public class PhoneEnum
{
public string Name {get; init;}
public string Prefix {get;init;}
public string DialCode {get;init;}
private PhoneEnum(string name, string prefix, string dialCode)
{
Name = name;
Prefix = prefix;
DialCode = dialCode;
}

public readonly static Swiss(nameof(Swiss), "CH", "+44");
public readonly static Martian(nameof(Martian), "MS", "+++");

public string ToE164Number(string phoneNumber)
{
return // do stuff here
}
}

string e164PhoneNumber = PhoneEnum.Swiss.ToE164Number(somePhoneNumber);
public class PhoneEnum
{
public string Name {get; init;}
public string Prefix {get;init;}
public string DialCode {get;init;}
private PhoneEnum(string name, string prefix, string dialCode)
{
Name = name;
Prefix = prefix;
DialCode = dialCode;
}

public readonly static Swiss(nameof(Swiss), "CH", "+44");
public readonly static Martian(nameof(Martian), "MS", "+++");

public string ToE164Number(string phoneNumber)
{
return // do stuff here
}
}

string e164PhoneNumber = PhoneEnum.Swiss.ToE164Number(somePhoneNumber);
There's some fancy packages that make smart enums
Mekasu0124
Mekasu0124OP13mo ago
I think it would be easier if I had the user select the numbers prefix from a list tbh
Mayor McCheese
Mayor McCheese13mo ago
yep
Mekasu0124
Mekasu0124OP13mo ago
so like they would select the prefix from the list, and then I would use that prefix against the dictionary to pull the country 2 letter code for the format so now to create a function to generate a dictionary of all countries codes and prefixes
Mekasu0124
Mekasu0124OP13mo ago
Stack Overflow
UWP get country phone number prefix
I want to get the country prefix for phone numbers. e.g. if I am in the US and I enter the number 0123 - 456, I want to get the prefix +1 or 001, so the number in the end is (+1) 0123 - 456 If I a...
Mekasu0124
Mekasu0124OP13mo ago
if I use that list, I can just pull those prefixes from that dictionary and display them and use them for the formatting
Mayor McCheese
Mayor McCheese13mo ago
I would at least serialize the list the world is a troubled place and things change globally more often than folks think 7 digit phone numbers became the US standard in 1967 for instance but you're concerned more about dial codes
Mekasu0124
Mekasu0124OP13mo ago
so given that I used that list from the stack overflow, how would I serialize it? Like what do you mean by that?
MODiX
MODiX13mo ago
Mayor McCheese
REPL Result: Success
var dictionary = new Dictionary<string, string>();

dictionary.Add("AC", "+247");
dictionary.Add("AD", "+376");
dictionary.Add("AE", "+971");
dictionary.Add("AF", "+93");
dictionary.Add("AG", "+1-268");
dictionary.Add("AI", "+1-264");
dictionary.Add("AL", "+355");
dictionary.Add("AM", "+374");
dictionary.Add("AN", "+599");
dictionary.Add("AO", "+244");
dictionary.Add("ZW", "+263");

System.Text.Json.JsonSerializer.Serialize(dictionary)
var dictionary = new Dictionary<string, string>();

dictionary.Add("AC", "+247");
dictionary.Add("AD", "+376");
dictionary.Add("AE", "+971");
dictionary.Add("AF", "+93");
dictionary.Add("AG", "+1-268");
dictionary.Add("AI", "+1-264");
dictionary.Add("AL", "+355");
dictionary.Add("AM", "+374");
dictionary.Add("AN", "+599");
dictionary.Add("AO", "+244");
dictionary.Add("ZW", "+263");

System.Text.Json.JsonSerializer.Serialize(dictionary)
Result: string
{"AC":"\u002B247","AD":"\u002B376","AE":"\u002B971","AF":"\u002B93","AG":"\u002B1-268","AI":"\u002B1-264","AL":"\u002B355","AM":"\u002B374","AN":"\u002B599","AO":"\u002B244","ZW":"\u002B263"}
{"AC":"\u002B247","AD":"\u002B376","AE":"\u002B971","AF":"\u002B93","AG":"\u002B1-268","AI":"\u002B1-264","AL":"\u002B355","AM":"\u002B374","AN":"\u002B599","AO":"\u002B244","ZW":"\u002B263"}
Compile: 613.139ms | Execution: 46.191ms | React with ❌ to remove this embed.
MODiX
MODiX13mo ago
Mayor McCheese
REPL Result: Success
var dictionary = new Dictionary<string, string>();

dictionary.Add("AC", "+247");
dictionary.Add("AD", "+376");
dictionary.Add("AE", "+971");
dictionary.Add("AF", "+93");
dictionary.Add("AG", "+1-268");
dictionary.Add("AI", "+1-264");
dictionary.Add("AL", "+355");
dictionary.Add("AM", "+374");
dictionary.Add("AN", "+599");
dictionary.Add("AO", "+244");
dictionary.Add("ZW", "+263");

var s = System.Text.Json.JsonSerializer.Serialize(dictionary);
var d = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(s);
d["AC"]
var dictionary = new Dictionary<string, string>();

dictionary.Add("AC", "+247");
dictionary.Add("AD", "+376");
dictionary.Add("AE", "+971");
dictionary.Add("AF", "+93");
dictionary.Add("AG", "+1-268");
dictionary.Add("AI", "+1-264");
dictionary.Add("AL", "+355");
dictionary.Add("AM", "+374");
dictionary.Add("AN", "+599");
dictionary.Add("AO", "+244");
dictionary.Add("ZW", "+263");

var s = System.Text.Json.JsonSerializer.Serialize(dictionary);
var d = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(s);
d["AC"]
Result: string
+247
+247
Compile: 641.178ms | Execution: 44.158ms | React with ❌ to remove this embed.
Mayor McCheese
Mayor McCheese13mo ago
so you just need a class that contains the dictionary, and can derserialize it
Mekasu0124
Mekasu0124OP13mo ago
https://pastebin.com/PbVveRmn ok so in my playground, I turned it into a function, however, I don't think I have the return type correct. I can't have the function be a void and I'm not sure what return type it is
Mayor McCheese
Mayor McCheese13mo ago
so, I wasn't super clear probably the point of serializing is that you can store it in a file ( as a for instance )
Mekasu0124
Mekasu0124OP13mo ago
would it be more efficient to store it in a file as opposed to just serializing and deserializing as needed on call?
Mayor McCheese
Mayor McCheese13mo ago
so you'd serialize the dictionary because countries to change, not frequently, but dial codes might change, countries might change, go away, change, etc. so then you're just replacing "a file" if you don't care about that and want to hard code it that's probably fine too the last country to get created was in 2011
Mekasu0124
Mekasu0124OP13mo ago
ok I'm with you
Mayor McCheese
Mayor McCheese13mo ago
also, depending on your audience you might want more or less dial codes
Mekasu0124
Mekasu0124OP13mo ago
apologies. discord took a crap. https://pastebin.com/bX8tnH8a I turned it into a class that I could use to not only get all of the prefixes for the drop down list, but to get dictionary from the json file and be able to match the selected prefix from the drop down to the matching country code for the formatter and create the file if it doesn't exists on run time. Thoughts?
Mayor McCheese
Mayor McCheese13mo ago
I'll look at it deeper in a bit
Jimmacle
Jimmacle13mo ago
you probably don't want to read in the file every time you call those methods
Mekasu0124
Mekasu0124OP13mo ago
ok what would be a better option?
Jimmacle
Jimmacle13mo ago
caching it only load it if you haven't already loaded it before
Mekasu0124
Mekasu0124OP13mo ago
ok. you can see my updated code at https://github.com/mekasu0124/MeksPhoneBook would you mind viewing it and telling me which file would be best for that and how I would do that?
Jimmacle
Jimmacle13mo ago
you'd add a property to keep your deserialized object and in your method have something to the effect of return MyObject ??= LoadMyObject();
Mekasu0124
Mekasu0124OP13mo ago
also, I have .vs in my .gitignore but it won't ignore that folder for some reason
Jimmacle
Jimmacle13mo ago
if you already commited files from that folder git will continue tracking them until deleted
Mekasu0124
Mekasu0124OP13mo ago
deleted from the repo or the workspace? I don't think I'm supposed to delete them?
Jimmacle
Jimmacle13mo ago
the repo then delete them, commit, then put them back it's just VS metadata either way, it won't break anything permanently hence not needing to commit them in the first place
Mekasu0124
Mekasu0124OP13mo ago
oh ok. I got you
Mayor McCheese
Mayor McCheese13mo ago
The point of serializing the data is to not to have to redeploy code each time you make a change to data like that if this is a website, do you want to redeploy because you remove some contries, or add some countries?
Mekasu0124
Mekasu0124OP13mo ago
I do apologize, but I don't think I'm fully understanding with this part. Where would I do this at? Like which file and how? I don't believe I've done this before. My CountryCodes class handles creating the file and then I just load the file and pull the resources I need
public class CountryCodes
{
public void CreateCodesFile()
{
var serializedData = JsonSerializer.Serialize(CountryCodeDictionary());
File.WriteAllText("country_codes.json", serializedData);
}
public List<string> GetAllPrefixes() {...}
public Dictionary<string, string> GetAllCountryCodes() {...}
public Dictionary<string, string> CountryCodeDictionary() {...}
public class CountryCodes
{
public void CreateCodesFile()
{
var serializedData = JsonSerializer.Serialize(CountryCodeDictionary());
File.WriteAllText("country_codes.json", serializedData);
}
public List<string> GetAllPrefixes() {...}
public Dictionary<string, string> GetAllCountryCodes() {...}
public Dictionary<string, string> CountryCodeDictionary() {...}
Mayor McCheese
Mayor McCheese13mo ago
the easiest way is to have your class take a dictionary in the constructor and disconnect the two aspects
Jimmacle
Jimmacle13mo ago
yeah, if you don't want to lazy load then just load it in/before the constructor and i would personally deploy the "default" list as an embedded resource instead of manually creating it in code, then copy it to the filesystem if one doesn't exist
Mayor McCheese
Mayor McCheese13mo ago
again, this is regulatory/technical data that isn't subject to change, you can viably hard code it as well; it'll change very infrequently
Mekasu0124
Mekasu0124OP13mo ago
ok. do you mind if I show you the path of usage for the CountryCodes? Maybe that can help better explain it and help me figure this out more easily?
public override void OnFrameworkInitializationCompleted()
{
base.OnFrameworkInitializationCompleted();

if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
var db = new Database();
var cc = new CountryCodes();
var gvs = new GithubService();

if (!File.Exists("main.db")) { db.CreateDatabase(); }
if (!File.Exists("country_codes.json")) { cc.CreateCodesFile(); }

desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(db, gvs),
};
}
}
public override void OnFrameworkInitializationCompleted()
{
base.OnFrameworkInitializationCompleted();

if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
var db = new Database();
var cc = new CountryCodes();
var gvs = new GithubService();

if (!File.Exists("main.db")) { db.CreateDatabase(); }
if (!File.Exists("country_codes.json")) { cc.CreateCodesFile(); }

desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(db, gvs),
};
}
}
ok so the code block above is my App.axaml.cs. When the program starts, it checks if the json file holding the country codes exists, and if it doesn't then it calls to create the codes, and then that class instance is passed to main window view model.
public class MainWindowViewModel : ViewModelBase
{
ViewModelBase _content;
private Database _db;
private GithubService _gvs;
private CountryCodes _cc;

private ContactModel _selectedContact;

public MainWindowViewModel(Database db, GithubService gvs, CountryCodes cc)
{
_db = db;
_gvs = gvs;
_cc = cc;
CheckForUpdate(_db, _cc);
}

public void ShowHomeScreen(Database db, CountryCodes cc)
{
var vm = new HomeScreenViewModel(db);

Observable.Merge(
vm.NewContact
.Do(_ => CreateNewUser(db, cc))
)
.Take(1)
.Subscribe();
Content = vm;
}

public void CreateNewUser(Database db, CountryCodes cc)
{
var vm = new NewUserViewModel(db, cc);
Content = vm;
}
public class MainWindowViewModel : ViewModelBase
{
ViewModelBase _content;
private Database _db;
private GithubService _gvs;
private CountryCodes _cc;

private ContactModel _selectedContact;

public MainWindowViewModel(Database db, GithubService gvs, CountryCodes cc)
{
_db = db;
_gvs = gvs;
_cc = cc;
CheckForUpdate(_db, _cc);
}

public void ShowHomeScreen(Database db, CountryCodes cc)
{
var vm = new HomeScreenViewModel(db);

Observable.Merge(
vm.NewContact
.Do(_ => CreateNewUser(db, cc))
)
.Take(1)
.Subscribe();
Content = vm;
}

public void CreateNewUser(Database db, CountryCodes cc)
{
var vm = new NewUserViewModel(db, cc);
Content = vm;
}
and in my MainWindowViewModel that CountryCodes cc is then passed to the view model for NewUserViewModel
public class NewUserViewModel : ViewModelBase
{
private Database _db;
private CountryCodes _cc;

public List<string> _prefList;
public string _pref;
public string _fn;
public string _ln;
public List<string> _suffList;
public string _suff;
public string _em;
public List<string> _phnPrefix;
public string _phnm;
public string _str;
public string _ct;
public string _st;
public string _zip;
public string _addr;
public string _dob;

public NewUserViewModel(Database db, CountryCodes cc)
{
_db = db;
_cc = cc;

PrefList = GetPrefixList();
SuffList = GetSuffixList();
PhonePrefix = _cc.GetAllPrefixes();


Back = ReactiveCommand.Create(() => { });
}
public class NewUserViewModel : ViewModelBase
{
private Database _db;
private CountryCodes _cc;

public List<string> _prefList;
public string _pref;
public string _fn;
public string _ln;
public List<string> _suffList;
public string _suff;
public string _em;
public List<string> _phnPrefix;
public string _phnm;
public string _str;
public string _ct;
public string _st;
public string _zip;
public string _addr;
public string _dob;

public NewUserViewModel(Database db, CountryCodes cc)
{
_db = db;
_cc = cc;

PrefList = GetPrefixList();
SuffList = GetSuffixList();
PhonePrefix = _cc.GetAllPrefixes();


Back = ReactiveCommand.Create(() => { });
}
and in my NewUserViewModel (which should have been named new contact) uses that _cc to get the list of number prefixes from the file like +1, +41, etc. So with me passing the class around like I am, and using that class instance to call the functions appropriate to the screen, that's how I get access to the information. I have updated my code on my repo https://github.com/mekasu0124/MeksPhoneBook. I just don't guess I'm understanding what you guys mean. What file would I cache my json file in, and how would I cache it? I do apologize for seeming stupid. I hope I don't upset you guys
Want results from more Discord servers?
Add your server