Phantom033
Phantom033

Reputation: 33

What can I do in order to restrict user from entring letter (a,b,c,d..) and other characters (<,>,@<,!...)

So I managed to kind of solve that problem, but I'm pretty sure there is a better way to do it. Plus, the second while statement works, but if I enter 6 digits, the first while won't apply to the input.

        inputNumber = Console.ReadLine();

        // checks if the value entered by user consists of 5 numbers
        while (inputNumber.Length != 5)
        {
            // if the length of the value doesn't equal to 5, the program
            // prompts the user to enter a valid number until there are 5 digits
            Console.WriteLine("Please make sure you are entering a 5-Digit number.");
            Console.WriteLine("Enter a 5-digit Number:");
            inputNumber = Console.ReadLine();
        }

        //  checks if there are any letters in the input
        while (inputNumber.Contains("a") ||
                inputNumber.Contains("b") ||
                inputNumber.Contains("c") ||
                inputNumber.Contains("d") ||
                inputNumber.Contains("e")) // and so on
        {
            Console.WriteLine("You can only use integer values! Please try again:");
            inputNumber = Console.ReadLine();
        }

Upvotes: 2

Views: 73

Answers (1)

TheGeneral
TheGeneral

Reputation: 81513

You can use regex, which is a very common and powerful string input validation tool:

Update : I am using [0-9] instead of \d which is a fair comparison with the old school way to match ascii digits only

!Regex.IsMatch(inputNumber, @"[0-9]{" + N + "}$", RegexOptions.ECMAScript)

or

Update : I have added ascii comparison and using c#9 patterns

inputNumber.Length != 5 || !inputNumber.All(x => x is >= '0' and <= '9')

or super old-school and efficient:

Update : I have added c#9 patterns

public bool Validate(str input)
{
   if (_str.Length != 5)
      return false;
   foreach (var c in _str)
      if (c is < '0' or > '9')
         return false;
   return true;
}

Note: In all these examples you only need one loop as they perform both length and digit evaluation.

Example

while (inputNumber.Length != 5 || !inputNumber.Any(char.IsDigit))
{
    ...
    Console.WriteLine("Please make sure you are entering a 5-Digit number.");
    Console.WriteLine("Enter a 5-digit Number:");
    inputNumber = Console.ReadLine();
}

However, for no good reason whatsoever, let's benchmark them with varying length input

Benchmarks

Setup

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18363.1316 (1909/November2018Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET Core SDK=5.0.102
  [Host]        : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
  .NET Core 5.0 : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT

Job=.NET Core 5.0  Runtime=.NET Core 5.0

Results

Method N Mean Error StdDev
CompiledRegex 5 45.814 ns 0.5341 ns 0.4996 ns
Linq 5 39.255 ns 0.8159 ns 0.9396 ns
OldSchool 5 2.747 ns 0.0068 ns 0.0053 ns
CompiledRegex 1000 549.921 ns 3.3407 ns 3.1249 ns
Linq 1000 5,727.363 ns 107.6484 ns 150.9081 ns
OldSchool 1000 382.726 ns 0.1857 ns 0.1450 ns
CompiledRegex 10000 5,017.362 ns 11.0595 ns 9.8039 ns
Linq 10000 57,502.325 ns 218.1421 ns 204.0503 ns
OldSchool 10000 3,764.997 ns 3.4676 ns 3.0739 ns

Code

[SimpleJob(RuntimeMoniker.NetCoreApp50)]
public class Test
{

   [Params(5, 1000, 10000)]
   public int N;

   private string _str;
   private Regex _compiledRegex;

   [GlobalSetup]
   public void Setup()
   {
      var r = new Random(42);
      _str = string.Concat(Enumerable.Range(0, N).Select(x => (char)r.Next('0', '9')));
      _compiledRegex = new Regex(@"[0-9]{" + N + "}$", RegexOptions.Compiled|RegexOptions.ECMAScript);

   }

   [Benchmark]
   public bool CompiledRegex() => !_compiledRegex.IsMatch(_str);

   [Benchmark]
   public bool Linq() => _str.Length != N || !_str.All(x => x is >= '0' and <= '9');

   [Benchmark]
   public bool OldSchool()
   {
      if (_str.Length != N)
         return false;
      foreach (var c in _str)
         if (c is < '0' or > '9')
            return false;
      return true;
   }
}

Summary

Update : Regex got a little faster, linq stayed about the same

  • Lesson 1, This was completely unnecessary and a waste of time. Pick your favorite

  • Lesson 2, Don't bring linq to a jitter optimized foreach party

Upvotes: 4

Related Questions