using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using static System.Console;
private const string InputParameter = "--input";
private const string PatternLengthParameter = "--patternLength";
private static readonly string ExpectedUsage = $"Expected usage: {InputParameter} <string> {PatternLengthParameter} <integer>";
static void Main(string[] args)
args = "--input zf3kabxcde224lkzf3mabxc51+crsdtzf3nab= --patternLength 3".Split(' ');
WriteLine("----------------------------------------");
WriteLine("Hello! Welcome to the pattern matcher!");
WriteLine("----------------------------------------");
WriteLine(ExpectedUsage);
WriteLine("Validating input . . .");
WriteLine("Getting input . . .");
var input = args.SkipWhile(p => !p.Equals(InputParameter, StringComparison.CurrentCultureIgnoreCase)).Skip(1).FirstOrDefault();
var patternLength = Convert.ToInt32(args.SkipWhile(p => !p.Equals(PatternLengthParameter, StringComparison.CurrentCultureIgnoreCase)).Skip(1).FirstOrDefault());
WriteLine(InputParameter + " " + input);
WriteLine(PatternLengthParameter + " " + patternLength);
var patterns = GetPatternMatches(input, patternLength);
WriteLine("End of Results");
private static List<PatternMatch> GetPatternMatches(string input, int patternLength)
var patterns = new List<PatternMatch>();
for (var i = 0; i < input?.Length; i++)
if (input.Length - i < patternLength) break;
var pattern = input.Substring(i, patternLength);
var existingMatchingPattern = patterns.FirstOrDefault(p => p.Pattern.Equals(pattern, StringComparison.CurrentCultureIgnoreCase));
if (existingMatchingPattern != null) existingMatchingPattern.MatchCount++;
patterns.Add(new PatternMatch()
Pattern = input.Substring(i, patternLength),
return patterns.Where(p => p.MatchCount > 1).ToList();
#endregion solution Method
private static void PrintSolution(List<PatternMatch> patterns)
foreach (var patternMatch in patterns)
WriteLine($"pattern {patternMatch.Pattern} occurs {patternMatch.MatchCount} times");
#region Validation Methods
private static void ValidateInput(string[] args)
if (args == null || !args.Any()) throw new ValidationException("No parameters found! " + ExpectedUsage);
var errorMessages = new List<string>();
errorMessages.AddRange(GetParameterNameErrors(args));
if (errorMessages.Any()) throw new ValidationException(string.Join('\n', errorMessages));
errorMessages.AddRange(GetParameterValueErrors(args));
if (errorMessages.Any()) throw new ValidationException(string.Join('\n', errorMessages));
private static IEnumerable<string> GetParameterNameErrors(string[] args)
var errorMessages = new List<string>();
if (!args.Any(p => p.Equals(InputParameter, StringComparison.CurrentCultureIgnoreCase))) errorMessages.Add($"Missing {InputParameter} parameter!");
if (!args.Any(p => p.Equals(PatternLengthParameter, StringComparison.CurrentCultureIgnoreCase))) errorMessages.Add($"Missing {PatternLengthParameter} parameter!");
private static IEnumerable<string> GetParameterValueErrors(string[] args)
var errorMessages = new List<string>();
var input = args.SkipWhile(p => !p.Equals(InputParameter, StringComparison.CurrentCultureIgnoreCase)).Skip(1).FirstOrDefault();
var patternLength = args.SkipWhile(p => !p.Equals(PatternLengthParameter, StringComparison.CurrentCultureIgnoreCase)).Skip(1).FirstOrDefault();
if (input == null || input.Equals(PatternLengthParameter, StringComparison.CurrentCultureIgnoreCase)) errorMessages.Add($"Please enter a valid string for {InputParameter}");
if (patternLength == null || !patternLength.All(char.IsDigit)) errorMessages.Add($"Please enter a valid integer for {PatternLengthParameter}");
#endregion Validation Methods
private class PatternMatch
public string Pattern { get; set; }
public int MatchCount { get; set; }