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

WB1975

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

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

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
您的第一个数字包含非数字值。这些空间将需要考虑。为什么需要正则表达式?

只需获取字符串中字符数的计数即可。如果计数超过条件限制,请告诉他们其无效的手机号码。

第一个数字缺少数字,如果您没有在论坛上发布实际的手机号码,我实际上更希望。因为这就是人们被垃圾邮件的方式。 ;)

我为您替换了网络前缀号。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,533
地点
弗吉尼亚州切萨皮克
编程经验
10+
我怀疑OP还试图通过检查电话号码的一部分以查看是否遵循以下电话号码方案,来验证该号码是否为有效的手机号码。 (例如,在美国,区号中的中间数字最初只能是0、1或2,直到他们在 北美编号方案。)通常,除非您知道要检查哪个国家(地区),否则您需要成为所有电话号码方案的专家。
 

WB1975

知名会员
已加入
2020年4月3日
留言内容
87
编程经验
Beginner
嗨,大家好

是的,我没有考虑移动电话号码,即使它不是我的,也很抱歉

我只希望能够检查前三个数字是
111
112
例如113,其余的都是数字,且长度不少于或不超过10位。
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,049
地点
挪威
编程经验
10+
首先,我认为Regex.Replace可以删除不相关的字符(例如空格)(也可以是破折号,加号,括号),这比String的Replace或Remove方法更易于使用。
Then a Regex.IsMatch with pattern @"1{2}[1-3]\d{7}" is also easier than the alternative, which would be looping and checking things like string.Length, string.StartsWith and char.IsDigit.

当然,您也可以循环整个输入并检查每个字符,而忽略空格等,并保留数字的计数,但是在特定位置检查特定数字的模式会稍微困难一些。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
截图_130.jpg


以为我们可以为此玩一点。 :凉爽的:

这种方式不使用任何正则表达式或char.isdigit或解析。我坚持使用面向对象的方法,并定期检查按下了什么键,如果该键在0到9之间,则当检测到每个数字键时,字符串生成器会建立移动电话的值,然后返回帮助程序类调用代码方法,以便您可以重用字符串内置值。试试看,看看是否喜欢。它执行时间为0.32ms,我假设此代码的Regex版本会慢一些。
C#:
    public class Helper
    {
        private static readonly StringBuilder NumberBuilder = new StringBuilder();
        public string Number_Builder
        {
            get => NumberBuilder.ToString();
            set => NumberBuilder.Append(value);
        }
    }
    public class Keys_Constructor
    {
        public string Console_Key(char key)
        {
            Helper helper = new Helper();
            if (key >= '0' && key <= '9')
            {
                helper.Number_Builder = (Convert.ToString(key));
            }
            /* 为非数字添加其他条件 */
            return helper.Number_Builder.ToString();
        }
    }
    internal static class Program
    {
        internal static void Main()
        {
            Helper helper = Verify_Mobile_From_User();
            /* Do something with helper.Number_Builder */
        }
        private static Helper Verify_Mobile_From_User()
        {
            Console.Clear();
            Console.WriteLine("What is your mobile phone number?");
            Helper helper = new Helper();
            while (!Console.KeyAvailable && helper.Number_Builder != null && helper.Number_Builder.ToString().Length < 10)
            {
                Keys_Constructor keys_Constructor = new Keys_Constructor();
                keys_Constructor.Console_Key(Console.ReadKey(true).KeyChar);
                Console.SetCursorPosition(34, Console.CursorTop - 1);
                Console.WriteLine(helper.Number_Builder.ToString());
            }
            Console.WriteLine($"Mobile number verified : { helper.Number_Builder.ToString() }");
            return helper;
        }
    }
要仅获取网络提供商国家/地区代码的三位数,您可以在helpers string builder上调用substring,如下所示: string x = helper.Number_Builder.ToString().Substring(0, 3);

希望这可以帮助。
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
谢谢。约翰实际上是45行。

但我想看看您是否可以完全使用Regex进行操作,并在0.32ms内完成所有操作。你敢尝试吗? :p

实际上,我可以清理很多代码,并且可能会提高速度。 :)

尽管还不完全符合要求(本身含糊不清)
请解释?

它完成了所要求的。不是吗
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,049
地点
挪威
编程经验
10+
这是我的三个:
C#:
var input = "(+111) 2345-678"; // = Console.ReadLine()
input = Regex.Replace(input, "[() +-]", string.Empty);
var valid = Regex.IsMatch(input, @"1{2}[1-3]\d{7}");
输入示例不仅包含空格和数字,但我认为这将是不同位置电话号码的常见输入模式。
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,049
地点
挪威
编程经验
10+
如果您只想允许有效输入,给定的前缀和7位数字,则可以执行以下操作:
C#:
var prefixes = new string[] { "111", "112", "113" };
for (var i = 0; i < prefixes.Length; i++)
{
    Console.WriteLine($"{i + 1}: {prefixes[i]}");
}
Console.Write("Choose a prefix: ");
var prefix = 0;
while (!(prefix >= 1 && prefix <= prefixes.Length))
{
    prefix = GetDigit();
}
Console.Write("\nInput 7 digits phone number (space and dash allowed): ");
var digits = new System.Text.StringBuilder();
while (digits.Length < 7)
{
    digits.Append(GetDigit());
}
Console.Write($"\nPhone number: ({prefixes[prefix - 1]}) {int.Parse(digits.ToString()):000 00 00}");
Console.ReadKey(true);
连同辅助方法:
C#:
static int GetDigit()
{
    var input = new ConsoleKeyInfo();
    while (!char.IsDigit(input.KeyChar))
    {
        input = Console.ReadKey(true);
        //allow some formatting chars in input
        if ("- ".Contains(input.KeyChar))
        {
            Console.Write(input.KeyChar);
        }
    }
    Console.Write(input.KeyChar);
    return (int)char.GetNumericValue(input.KeyChar);
}
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
这也是一个有趣的想法。但是,调用Regex所涉及的开销不仅成本高昂,而且正如我所证明的那样,它无关紧要。因此,如果您打算一次调用Regex,则最好将Regex用于其他所有功能,其中包括检查char.isdigit和value.Contains(input.KeyChar)和char.GetNumericValue。

我想我会坚持使用自己的方法。由于它不需要将正则表达式引入其中,它还允许数字以面向对象的方式传递。更不用说它在速度和性能上也占优势,并且在调用Regex不需要它的东西时没有额外的开销。我意识到我说了两次。 :哈哈:

当你45行"为非数字添加其他条件"至少让空格漏掉并且不验证其他字符,并且您还需要验证前三个数字。
好的,这是您的前缀:
C#:
        internal static void Main()
        {
            Helper helper = Verify_Mobile_From_User();
            string prefix = helper.Number_Builder.ToString().Substring(0, 3);
        }
这是您的空白处:
C#:
        if (key >= '0' && key <= '9' || key == ' ')
else条件只是报告非数字字符的一种保障。

编辑,删除不相关的嵌入式注释。
 
Last edited:

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
正则表达式是一个很重要的概念。您所做的事情不是必需的。我写的代码-是的,有45行代码,而Johns有35行代码。但是,由于使用Regex涉及大量开销,因此我的方法速度快两倍。直到Microsoft在下一个版本中解决此问题之前,我都会考虑使用Regex,因为它将不再受到任何此类开销的阻碍,因为据说下一个Microsoft版本将解决此问题。但在此之前,我建议您坚持使用非Regex版本。

顺便说一句,我不是Regex讨厌者,或者类似的东西。 @跳伞 知道我沉迷于Regex,并且经常使用它。但是在我看来,不值得将其用于像您正在做的事情一样简单的事情。选择实际上取决于您。 (y)
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
我知道约翰,我运行了您的代码。我实际上喜欢您的方式。尽管对我来说执行起来很慢。我稍后将重新运行它,因为我有敏锐的调查头脑来寻找应该比它们做得更好的事情。我想找到使它变慢的原因。

这就是为什么我说如果您在Regex中完成所有操作,那么开销会降低性能……这是我和Skydiver在另一块板上不知疲倦地讨论的话题,通过在使用Regex时运行单元测试以找出性能问题并将它们与Linq和传统的基本代码概念。显然,Regex在性能方面不及其他。但是微软正在计划并承诺在未来几周内发布一个重大版本,它将一劳永逸地解决这些问题。补丁程序的目标将意味着使用Regex时,性能将不再有任何开销成本。

但是,如果您也要在其中使用RegEx。这样会更慢。单独使用RegEx可能会更快,但是使用三行代码的时间与我的方法一样长。当然,差异只有几毫秒。但是,如果您碰巧一次要处理数千个手机号码,那就成了问题。并不是说我们的OP正在这样做。我只是从类推的角度说。
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,049
地点
挪威
编程经验
10+
使用Any和All扩展名的另一个变体:
C#:
var input = "111-2345 678"; // = Console.ReadLine()
var remove = " -".ToCharArray();
var prefixes = new string[] { "111", "112", "113" };
Array.ForEach(remove, c => input = input.Replace(c.ToString(), string.Empty));
var valid = input.Length == 10 && input.All(c => char.IsDigit(c)) && prefixes.Any(s => input.StartsWith(s));
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
我认为您可以将速度从137ms大大提高到John。如果您不介意我的批评,您会非常优雅地写这本书,以防万一。

Coming at post #11 from a performance point only, One line executions with no set conditions would execute at O(0) complexity. But for while and for iterations, they would be O( n ), 'n' equals the number of required loops and this depends if there are conditions to be met. If there are conditions, they would execute as O(1) So, if we needed to iterate 20000 cycles : for (int integer = 0; integer < 20000; integer++). This would accumulate to O(20000) because the iteration cycle would be 20000 per the total iterations. Where this gets slow is when you factor in if additional loops, Then you get to O(n*2) complexity for calling the additional while loop, and this isn't efficient for performance when you add if conditions which add O(1) complexity. This is why I almost always try to avoid nested loops. I'm noticing a performance decrease when I enter into the GetDigit() 称呼。

啊,现在你在说话。如果不运行与其他示例集成的Linq查询,它的运行时间为5ms,这很漂亮。将Linq的因数更改为您的示例,我可以输出0.25ms。完美的性能。 (y)
 
Last edited:

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
我不得不再去一次。只有我在其中添加了一些额外的内容,例如退格。请注意,这可能与某些调整有关。我还添加了在上一个中忽略的前缀检查。 :
C#:
    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)
            {
                char Key = Console.ReadKey(true).KeyChar;
                if (" -|".Contains(Key.ToString()))
                {
                    number_Builder.IsSeparated(Key);
                }
                else if (char.IsDigit(Key))
                {
                    numberConstructor = number_Builder.IsNumber(Key, numberConstructor);
                    if (numberConstructor.Length == 3)
                    {
                        hasPrefix = true; number_Builder.MobilePrefix = numberConstructor.ToString().Substring(0, 3);
                    }
                    else hasPrefix = false;
                }
                else if (numberConstructor.Length != 0 && Console.ReadKey().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.ToString().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 = { "111", "112", "113" };
        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;
        }
    }
有待改进。有没有人? :凉爽的: 建议的改进也欢迎。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,533
地点
弗吉尼亚州切萨皮克
编程经验
10+
尝试支持退格的不错的补充。不幸的是,当用户输入数字并尝试反向间隔时,反向间隔仅支持幸福路径。不幸的是,如果用户键入“ 0”,“ A”,“ 1”或“ 0”,则操作不会很好<space> '1' .

稍后,我将尽一切乐趣,并展示我在交互式验证中的尝试。
 
最佳 底部