Search code examples
c#winformsclassexceptionget

Whats wrong with these regex validation and exceptions?


This is an update to an older question. Im making a windows forms app to request contact information. I created a class to trim the input text and check if the textbox is empty. I also assigned patterns for the email and phonenumber. However the text isnt following the regex and isnt catching any exceptions either.

the form only has one button and it should compile and present the information inserted into the textbox.

I used the Get request method for the strings collected from the textbox.

  bool GetPhone(ref string phonenumber)
    {
        bool success = true;
        try
        {
            txtPhone.Text=Input.TrimText(txtPhone.Text);
            if (Input.IsTextEmpty(txtPhone.Text))
                throw new InputRequiredException();

            phonenumber = txtPhone.Text;
            Regex Regphone = new Regex(@"^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$");
            Match matchphone = Regphone.Match(phonenumber);
            if (matchphone.Success)
                success = true;
            else throw new InputRequiredException();
        }
        catch(Exception error)
        {
            string remediation = "Enter a valid phone number.";
            Input.ShowError(error, remediation);
            Input.SelectText(txtPhone);
        }
        try
        {
            int Phone = Convert.ToInt32(txtPhone.Text);

            success = true;
        }
        catch (Exception error)
        {
            string remediation = "Enter a valid phone number.";
            Input.ShowError(error, remediation);
            Input.SelectText(txtPhone);

        }
            return success;
    }

And a class.

 class Input
{
 static public string TrimText(string A)
{
    return A.Trim();
}

internal static bool IsTextEmpty(string A)
{
    if (string.IsNullOrEmpty(A))
    {
        return true;
    }

    else
    {
        return false;
    }
}

internal static void ShowError(object error, string remediation)
{

}

static public void SelectText(TextBox textBox1)
{
     textBox1.SelectAll();
}
}

Exception Class

 internal class InputRequiredException : Exception
{
    public InputRequiredException()
    {
    }

    public InputRequiredException(string message) : base(message)
    {
        message = "Invalid Input.";
    }

    public InputRequiredException(string message, Exception innerException) : base(message, innerException)
    {
    }

    protected InputRequiredException(SerializationInfo info, StreamingContext context) : base(info, context)
    {
    }
}

There are no errors showing in the code and the program runs smoothly but I am not getting the desired output. What I need is for the phone number textbox to validate the input and throw an exception if it is wrong. Currently, the textbox is accepting any and all values, without any exceptions. I am an utter noob when it comes to coding and understand the code might have logical errors. Whether there is one mistake or multiple or if the code is simply unfinished please feel free to let me know.


Solution

  • Welcome to SO. I'm wondering if it wouldn't be simpler for both you and the user to simply require the 10 numbers associated with the phone number rather than those same 10 numbers in a specific format?

    For instance, one user might give you 5559140200 and another might give you (555) 914-0200. Perhaps the format is just trivial enough to ignore, freeing you up to simply check the numeric sequence rather than focus on what formatting may or may not be present? This way, you can both limit the textbox to numerical input only and restrict to a minimum and maximum of 10 characters.

    If you're looking to standardize input for database entry or to compare with a standardized database record, you could take their 10-number sequence, format it after it's provided then record or compare. This way, neither you nor your users are bound by rigidity at input and you can just apply this after the enter key has been pressed...

    String.Format("{0:(###)###-####}", 5559140200);
    

    ... to effectively arrive at your target of (555)914-0200 without regex.

    If that isn't what you're aiming for, perhaps a different regex pattern...

    Regex Regphone = new Regex(@"\([0-9]{3}\)[0-9]{3}\-[0-9]{4}");
    

    As requested in comments, below is an example of the String.Format() route that mitigates thrown exceptions...

    using System;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    
    namespace phone_number_sanitizer
    {
        public partial class Form1 : Form
        {
            #region Variables
            string phonenumber = "";
            string[] msg = new string[] { "Enter a valid phone number.", "Other messages you may wish to include." }; // referenced by array index
            #endregion
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                #region UI Setup
                txtPhone.MaxLength = 10;
                btnSubmit.Enabled = false;
                #endregion
            }
    
            private void txtPhone_TextChanged(object sender, EventArgs e)
            {
                /*
                txtPhone's MaxLength is set to 10 and a minimum of 10 characters, restricted to numbers, is
                required to enable the Submit button. If user attempts to paste anything other than a numerical
                sequence, user will be presented with a predetermined error message.
                */
                if (txtPhone.Text.Length == 10) { btnSubmit.Enabled = true; } else { btnSubmit.Enabled = false; }
                if (Regex.IsMatch(txtPhone.Text, @"[^0-9]"))
                {
                    DialogResult result = MessageBox.Show(msg[0], "System Alert", MessageBoxButtons.OK);
                    if (result == DialogResult.OK)
                    {
                        txtPhone.Text = "";
                        txtPhone.Focus();
                        btnSubmit.Enabled = false;
                    }
                }
            }
    
            private void txtPhone_KeyPress(object sender, KeyPressEventArgs e)
            {
                /*
                Here, you check to ensure that an approved key has been pressed. If not, you don't add that character
                to txtPhone, you simply ignore it.
                */
                if (Regex.IsMatch(e.KeyChar.ToString(), @"[^0-9]") && e.KeyChar != (char)Keys.Back) { e.Handled = true; }
            }
    
            private void btnSubmit_Click(object sender, EventArgs e)
            {
                /*
                By this phase, the Submit button could only be enabled if user provides a 10-digit sequence. You will have no
                more and no less than 10 numbers to format however you need to.
                */
                try
                {
                    phonenumber = String.Format("{0:(###)###-####}", txtPhone.Text);
                }
                catch { }
            }
        }
    }
    

    A combination of controlling the input to a sequence of numbers with auto-formatting directly within the textbox is as follows:

    using System;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    
    namespace phone_number_sanitizer
    {
        public partial class Form1 : Form
        {
            #region Variables
            string phonenumber = "";
            string[] msg = new string[] { "Enter a valid phone number.", "Other messages you may wish to include." };
            #endregion
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                #region UI Setup
                txtPhone.MaxLength = 13;
                btnSubmit.Enabled = false;
                #endregion
            }
    
            private void txtPhone_TextChanged(object sender, EventArgs e)
            {
                if (txtPhone.Text.Length == 10 && Regex.IsMatch(txtPhone.Text, @"[0-9]")
                {
                    btnSubmit.Enabled = true;
                    txtPhone.Text = txtPhone.Text.Insert(6, "-").Insert(3, ")").Insert(0, "(");
                    txtPhone.SelectionStart = txtPhone.Text.Length;
                    txtPhone.SelectionLength = 0;
                }
                else if (txtPhone.Text.Length == 13 && Regex.IsMatch(txtPhone.Text, @"\([0-9]{3}\)[0-9]{3}\-[0-9]{4}"))
                {
                    btnSubmit.Enabled = true;
                }
                else
                {
                    btnSubmit.Enabled = false;
                    txtPhone.Text = txtPhone.Text.Replace("(", "").Replace(")", "").Replace("-", "");
                    txtPhone.SelectionStart = txtPhone.Text.Length;
                    txtPhone.SelectionLength = 0;
                }
            }
    
            private void txtPhone_KeyPress(object sender, KeyPressEventArgs e)
            {
                if (Regex.IsMatch(e.KeyChar.ToString(), @"[^0-9]") && e.KeyChar != (char)Keys.Back) { e.Handled = true; }
            }
    
            private void btnSubmit_Click(object sender, EventArgs e)
            {
                try
                {
                    phonenumber = txtPhone.Text;
                }
                catch { /* There's nothing to catch here so the try / catch is useless. */}
            }
        }
    }
    

    It's a little more sophisticated and you get out of the textbox exactly what you want without having to rely on the user to give it to you. With this alternative, your users have the option to either key-in their 10-digit phone numbers and have the formatting done dynamically or they can paste a number that's formatted accordingly, i.e. "(555)941-0200". Either option will enable the submit button.

    Both of these option are presented to allow you the ability to control the input. It's sometimes better to eliminate the potential for input errors than it is to pop error messages when mistakes occur. With these, there's no way a user is going to provide you with anything other than either a raw 10-digit numerical sequence or a formatted 10-digit phone number and what you get is exactly what you want without any hassles.