解决 从用户那里获取手机号码

WB1975

知名会员
已加入
2020年4月3日
留言内容
87
编程经验
Beginner
如果我希望用户在控制台应用程序中输入手机号码
因此用户只能输入
011 086 087开始,然后是7位数字
如0142223434

最好用正则表达式来完成吗?或者,还有更好的方法?
 
由主持人最后编辑:

羊皮

知名会员
已加入
2018年9月5日
留言内容
1,982
编程经验
10+
It's always fun to turn one of these into a little game. Look forward to what you come up with. I've made some changes already. I should have been reading the Key as ConsoleKeyInfo instead of char. This way I can read both the key on line 36 and chars. Now it should work fine.
第19版后的新改进:
using System;
using System.Linq;
using System.Text;

namespace TestConsoleApp
{
    internal static class Program
    {
        internal static void Main()
        {
            Execute();
        }

        internal static void Execute()
        {
            Console.WriteLine("What's your mobile phone number?");
            Number_Builder number_Builder = new Number_Builder();
            StringBuilder numberConstructor = new StringBuilder();
            bool hasPrefix = false;
            while (number_Builder.MobileNumber.Length < number_Builder.ContainsSeparater)
            {
                ConsoleKeyInfo Key = Console.ReadKey(true);
                if (" -|".Contains(Key.KeyChar.ToString()))
                {
                    number_Builder.IsSeparated(Key.KeyChar);
                }
                else if (char.IsDigit(Key.KeyChar))
                {
                    numberConstructor = number_Builder.IsNumber(Key.KeyChar, numberConstructor);
                    if (numberConstructor.Length == 3)
                    {
                        hasPrefix = true; number_Builder.MobilePrefix = numberConstructor.ToString().Substring(0, 3);
                    }
                    else hasPrefix = false;
                }
                else if (numberConstructor.Length != 0 && Key.Key == ConsoleKey.Backspace)
                {
                    numberConstructor.Length--;
                }
                if (hasPrefix && !number_Builder.IsAllowed_Prefix())
                {
                    Console.Clear();
                    Console.WriteLine($"The { numberConstructor } network provider is not allowed. We allow { number_Builder.AllowedPrefix[0] }, { number_Builder.AllowedPrefix[1] }, { number_Builder.AllowedPrefix[2] }. Try again.");
                    number_Builder.MobileNumber = string.Empty; numberConstructor.Length = 0; Console.WriteLine("What's your mobile phone number?");
                }
                Console.SetCursorPosition(34, Console.CursorTop - 1);
                Console.WriteLine(numberConstructor);
            }
            number_Builder.MobilePrefix = numberConstructor.ToString().Substring(0, 3);
            StringBuilder number_Constructor = new StringBuilder().Insert(0, string.Concat(number_Builder.MobilePrefix, number_Builder.SeperatorValues, number_Builder.MobileNumber.Remove(0, 3)));
            number_Builder.MobileNumber = numberConstructor.ToString();
            number_Builder.CosmeticNumber = number_Constructor.ToString();
            int MobileAsInt = Convert.ToInt32(number_Builder.MobileNumber);
            Console.WriteLine($"Prefix number verified : { number_Builder.MobilePrefix }");
            Console.WriteLine($"Mobile number verified : { number_Builder.MobileNumber }");
            Console.WriteLine($"Cosmetic number verified : { number_Builder.CosmeticNumber }");

        }
    }
    public class Number_Builder
    {
        public string SeperatorValues { get; set; } = string.Empty;
        public string MobilePrefix { get; set; } = string.Empty;
        public int ContainsSeparater { get; set; } = 10;
        public string MobileNumber { get; set; } = string.Empty;
        public string CosmeticNumber { get; set; } = string.Empty;
        public string[] AllowedPrefix = { "011", "012", "013" };
        public bool IsAllowed_Prefix()
        {
            return AllowedPrefix.Contains(MobilePrefix);
        }
        public void IsSeparated(char Value_In)
        {
            SeperatorValues = string.Concat(SeperatorValues, $"{Value_In}");
        }
        public StringBuilder IsNumber(char Number_In, StringBuilder num_Constructor)
        {
            MobileNumber = num_Constructor.Append(Number_In.ToString()).ToString();
            return num_Constructor;
        }
    }
}
 

WB1975

知名会员
已加入
2020年4月3日
留言内容
87
编程经验
Beginner
请做!

而且我也不介意看到使用常规代码和正则表达式的解决方案,这真的不会造成伤害。
 

跳伞者

工作人员
已加入
2019年4月6日
留言内容
2,611
地点
弗吉尼亚州切萨皮克
编程经验
10+
Just joining in on the fun. Currently the code for my ValidatedInput class is working, but the MaskedInput is still in its early phases, but I just wanted to show what it could possibly look like if you uncomment the first line to define USE_MASKED_INPUT.

无论如何,该代码显示了进行电话号码验证的3种方法。我花了一段时间才弄清楚,验证实际上是与接受有效输入不同的问题。因此,在我的实现中,"control" that implements the IValidatedInput interface fires an event giving the caller a chance to validate the data enter. I've done the Regex, LINQ, and plain old string inspection approaches of validation. What make this nice is that the validation method can be swapped around easily.

C#:
// #define USE_MASKED_INPUT
using System;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;

namespace PhoneNumberValidation
{
    public class ValidatingEventArgs : EventArgs
    {
        public bool IsValid { get; set; }
        public string Message { get; set; }
    }

    interface IValidatedInput
    {
        string Input { get; }
        bool IsValid { get; }

        event EventHandler<ValidatingEventArgs> Validating;

        string ReadInput(string prompt);
    }

    class ValidatedInput : IValidatedInput
    {
        public string Input { get; protected set; }
        public bool IsValid { get; protected set; }

        public event EventHandler<ValidatingEventArgs> Validating;

        public virtual string ReadInput(string prompt)
        {
            while (true)
            {
                Console.Write(prompt);
                Input = Console.ReadLine();
                if (IsInputValid(out string message))
                    return Input;
                Console.WriteLine(message);
            }
        }

        protected virtual bool IsInputValid(out string message)
        {
            var args = new ValidatingEventArgs();
            args.IsValid = true;
            args.Message = String.Empty;
            OnValidating(args);
            message = args.Message;
            IsValid = args.IsValid;
            return args.IsValid;
        }

        protected virtual void OnValidating(ValidatingEventArgs args) => Validating?.Invoke(this, args);
    }

#if USE_MASKED_INPUT
    class ConsoleState : IDisposable
    {
        public int CursorLeft { get; set; }
        public int CursorTop { get; set; }
        public ConsoleColor ForegroundColor { get; set; }
        public ConsoleColor BackgroundColor { get; set; }

        public ConsoleState()
        {
            Capture();
        }

        public void Capture()
        {
            CursorLeft = Console.CursorLeft;
            CursorTop = Console.CursorTop;
            ForegroundColor = Console.ForegroundColor;
            BackgroundColor = Console.BackgroundColor;
        }

        public void Restore()
        {
            Console.CursorLeft = CursorLeft;
            Console.CursorTop = CursorTop;
            Console.ForegroundColor = ForegroundColor;
            Console.BackgroundColor = BackgroundColor;
        }

        public void Dispose()
        {
            Restore();
        }
    }

    class MaskedInput : ValidatedInput
    {
        public string Mask { get; }

        public MaskedInput(string mask)
        {
            Mask = mask;
        }

        public override string ReadInput(string prompt)
        {
            using (var consoleState = new ConsoleState())
            {
                do
                {
                    consoleState.Restore();
                    DrawPrompt(prompt);
                    DrawMask();
                    ReadInputInternal();
                } while (!IsInputValid(out string message));

                consoleState.Capture();
            }
            return Input;
        }

        void DrawPrompt(string prompt) => Console.Write(prompt);

        void DrawMask()
        {
            using (var consoleState = new ConsoleState())
            {
                Console.BackgroundColor = ConsoleColor.Black;
                Console.ForegroundColor = ConsoleColor.DarkGray;
                Console.Write(Mask);

                consoleState.Restore();
                Console.ForegroundColor = ConsoleColor.DarkYellow;
                Console.Write(Input);
            }
        }

        void ReadInputInternal()
        {
            //$ TODO: Implement event for each keyed input to allow live validation.
            //$ TODO: Implement accepting only keys that match the mask.
            //$ TODO: Implement pressing escape.
            //$ TODO: Implement backspacing and arrowing.
            //$ TODO: Implement insert and overwride.

            Input = Console.ReadLine();
        }
    }
#endif  // USE_MASKED_INPUT

    class Program
    {
        static void Main(string[] args)
        {
#if USE_MASKED_INPUT
            var validatedInput = new MaskedInput("999 999 9999");
#else
            var validatedInput = new ValidatedInput();
#endif

            //
            // Uncomment one of the validation options below:
            //

            // validatedInput.Validating += OnValidating_Regex;
            // validatedInput.Validating += OnValidating_Linq;
            validatedInput.Validating += OnValidating_StringOps;

            var phoneNumber = validatedInput.ReadInput("Enter mobile number: ");
            if (validatedInput.IsValid)
                Console.WriteLine("{0} is {1}.", phoneNumber, validatedInput.IsValid ? "valid" : "invalid");
        }

        static void OnValidating_Regex(object obj, ValidatingEventArgs args)
        {
            IValidatedInput validatedInput = (IValidatedInput) obj;
            args.IsValid = Regex.Match(validatedInput.Input, @"11[123](-|\s)*[0-9]{3}(-|\s)*[0-9]{4}").Success;
            args.Message = args.IsValid ? "" : "Must match expected pattern.";
        }

        static string[] ValidPrefixes = new string[] { "111", "112", "113" };

        static void OnValidating_Linq(object obj, ValidatingEventArgs args)
        {
            IValidatedInput validatedInput = (IValidatedInput)obj;
            var input = validatedInput.Input;
            var charArray = input.ToCharArray();
            var digits = charArray.Where(ch => char.IsDigit(ch)).ToList();

            args.IsValid = false;

            args.Message = "Must contain 10 digits.";
            if (digits.Count != 10)
                return;

            args.Message = "Must consist of only digits, whitespace, and dashes.";
            if (!input.ToCharArray().All(ch => char.IsDigit(ch) || char.IsWhiteSpace(ch) || ch == '-'))
                return;

            args.Message = "Prefix must be one of " + string.Join(", ", ValidPrefixes);
            var prefix = digits.Take(3).Aggregate("", (s, ch) => s += ch);
            if (!ValidPrefixes.Contains(prefix))
                return;

            args.Message = "";
            args.IsValid = true;
        }

        static void OnValidating_StringOps(object obj, ValidatingEventArgs args)
        {
            IValidatedInput validatedInput = (IValidatedInput)obj;
            var input = validatedInput.Input;
            string digits = "";

            foreach (char ch in input)
            {
                if (char.IsDigit(ch))
                {
                    digits += ch;
                }
                else if (char.IsWhiteSpace(ch) || ch == '-')
                {
                    // do nothing
                }
                else
                {
                    args.IsValid = false;
                    args.Message = "Must consist of only digits, whitespace, and dashes.";
                    return;
                }
            }

            if (digits.Length != 10)
            {
                args.IsValid = false;
                args.Message = "Must contain 10 digits.";
                return;
            }

            var prefix = digits.Substring(0, 3);
            if (!ValidPrefixes.Contains(prefix))
            {
                args.IsValid = false;
                args.Message = "Prefix must be one of " + string.Join(", ", ValidPrefixes);
            }
        }
    }
}
 

跳伞者

工作人员
已加入
2019年4月6日
留言内容
2,611
地点
弗吉尼亚州切萨皮克
编程经验
10+
当然。问你的问题。

(对不起,我还没有机会重新完成掩盖的输入。本周我应该有更多的空闲时间。)
 

跳伞者

工作人员
已加入
2019年4月6日
留言内容
2,611
地点
弗吉尼亚州切萨皮克
编程经验
10+
在第153或155行,实例化了验证类的实例。在第164行,您告诉班级触发一个事件,要求验证用户输入的输入是否有效。在第166行,您告诉该类提示用户输入。在第167行,您检查以查看输入的使用真正有效(或者用户是否放弃了输入数据)。

在事件处理程序中(请参阅OnValidating_ *方法之一),您将使用用户到目前为止输入的字符串进行调用。您可以输入true或false来响应该输入是否有效。

使之成为可重用的类的原因在于,您现在可以专注于编写验证检查逻辑,并且该类负责样板输入循环逻辑。我还希望通过屏蔽的输入类显示的是,输入循环逻辑可以更复杂,并考虑单个按键并进行光标位置管理。这样,就有可能将用户的输入限制为仅一些有效键,并且如果我绕过掩蔽逻辑,则可以在特定位置使用一些有效键。

至于在其他项目中重用该类,您可以将该类编译到一个类库中。您的其他项目然后可以引用该程序集(又名DLL)。
 

WB1975

知名会员
已加入
2020年4月3日
留言内容
87
编程经验
Beginner
将类编译到类库中。您的其他项目然后可以引用该程序集(又名DLL)。 -那很难吗?是重用它的推荐方法还是有更好的方法?
 

跳伞者

工作人员
已加入
2019年4月6日
留言内容
2,611
地点
弗吉尼亚州切萨皮克
编程经验
10+
最佳 底部