6

I am trying to format phone numbers that are being looped in from my viewModel like so: (###) ###-#### without having to parse the string to a decimal.

This method gives a Formatting is specified, but argument is not IFormattable error:

@foreach (var client in Model.Clients)
{
    <td>@String.Format("{0:(###) ###-####}", client.TelephoneNumber)</td>
}

So, I would need to parse to a decimal:

@foreach (var client in Model.Clients)
{
    <td>@String.Format("{0:(###) ###-####}", Decimal.Parse(client.TelephoneNumber))</td>
}

But there is no guarantee that the numbers being looped in will be just digits so most likely at least one parse attempt will fail.

Is there a way to achieve this formatting without the need to Parse to a decimal?

cfly24
  • 1,882
  • 3
  • 22
  • 56
  • Provide a sample of the kind of data you expect. Then consider splitting the values as strings. As far as I know you won't be able to apply a format i.e `###-####` to the string. – Jasen Sep 22 '15 at 21:42
  • 1
    See here http://stackoverflow.com/questions/10512349/string-format-how-it-works-and-how-to-implement-custom-formatstrings – Jasen Sep 22 '15 at 21:44
  • You can try to apply regex filter to `client.TelephoneNumber` first to get only numerical digits, then move on from there. – DPac Sep 22 '15 at 21:46

3 Answers3

2

If your TelephoneNumber is a string you always can use substrings to format number. It's not so clean, but you don't need any separate libraries and convert to decimal:

        @String.Format("({0}) {1}-{2}"
            , client.TelephoneNumber.Substring(0, 3)
            , client.TelephoneNumber.Substring(3, 3)
            , client.TelephoneNumber.Substring(6, client.TelephoneNumber.Length - 6))
teo van kot
  • 12,350
  • 10
  • 38
  • 70
1

Try this, you may put it in a static function somewhere for repeated use.

var match = Regex.Match("1231231234", @"(\d{3})(\d{3})(\d{4})");
Console.WriteLine( "(" + match.Groups[1] + ") " + match.Groups[2] + "-" + match.Groups[3]);
Ghasan غسان
  • 5,577
  • 4
  • 33
  • 44
1

Or even easier if you are only dealing with 10 digit phone numbers:

Regex.Replace(phoneNum, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");

Read-Only

If you're only interested in displaying the phone number, you could make it an HTML helper like this:

public static MvcHtmlString FormatPhoneNum(this HtmlHelper helper, string phoneNum)
{
    //You could strip non-digits here to make it more robust

    if (String.IsNullOrEmpty(phoneNum)) return phoneNum;

    return new MvcHtmlString(Regex.Replace(phoneNum, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3"));  //US Phone Number
}

And then use like this:

@foreach (var client in Model.Clients)
{
    <td>@Html.FormatPhoneNumber(client.TelephoneNumber)</td>
}

Editing

If you also need to edit the phone number and want to display it formatted in the editor textbox, you can create a wrapper property on your view model to transform the phone number:

public class Client
{
    public string TelephoneNumber {get; set;}

    //Require 10 digits, each surrounded by any non-digit characters (will strip all non-digits)
    [RegularExpression(@"(\D*\d\D*){10}", ErrorMessage = "Please enter a 10 digit phone number")]
    public string FormattedPhoneNum
    {
        get
        {
            MyHelpers.FormatPhoneNumber(TelephoneNumber);
        }
        set
        {
            TelephoneNumber = MyHelpers.StripPhoneNumber(value);
        }
    }
}

public class MyHelpers
{
    public static StripPhoneNumber(string phone)
    {
        if (phone == null)
            return phone;
        else
            return _nonDigits.Replace(phone, String.Empty);
    }

    public static string FormatPhoneNumber(string phoneNum)
    {
        phoneNum = StripPhoneNumber(phoneNum);

        if (String.IsNullOrEmpty(phoneNum)) return phoneNum;

        return Regex.Replace(phoneNum, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");  //US Phone Number
    }
}

Note the RegularExpressionAttribute on the property. It takes a very lenient stance on user input. It is satisfied as long as the user enters at least 10 digits into the textbox regardless of any other characters typed in. You might need to make this more restrictive for your own purposes.

xr280xr
  • 12,621
  • 7
  • 81
  • 125