public static void Main()
var instance = new Program();
instance.BigStringTest("second thirtyseventh of it", 2, 37, 5);
private void BigStringTest(string syntax, int positionAsInt, int fractionAsInt, int desiredResultStringLength)
var series = "1234567890";
var seriesModulus = fractionAsInt % series.Length;
var bigStringBuilder = new StringBuilder();
for (int i = 0; i < (fractionAsInt - seriesModulus) / series.Length; i++)
bigStringBuilder.Append(series);
bigStringBuilder.Append(series.Substring(0, seriesModulus));
var fractionalString = bigStringBuilder.ToString();
for (int i = 2; i <= desiredResultStringLength; i++)
bigStringBuilder.Append(fractionalString);
var bigString = bigStringBuilder.ToString();
var expectedBigStringResult = new string(bigString.Skip(positionAsInt * desiredResultStringLength).Take(desiredResultStringLength).ToArray());
Console.WriteLine($"SYNTAX:\t{syntax}");
Console.WriteLine("\nVALUES:");
Array.ForEach(values, x => Console.WriteLine($"\t{x}"));
var results = GetSubstring(syntax, values);
Console.WriteLine("\nResults:");
Array.ForEach(results, x => Console.WriteLine($"\t{x}"));
Console.WriteLine("\n\n");
Console.WriteLine($"EXPECTED:\t{expectedBigStringResult}");
Console.WriteLine($"ACTUAL:\t\t{results[0]}");
Console.WriteLine(results[0] == expectedBigStringResult ? "TEST PASSED" : "TEST FAILED");
Console.WriteLine("\n\n\nExecution complete - press any key to terminate.");
private string[] GetSubstring(string syntax, string[] values)
ValidateParameters(syntax, values);
syntax = syntax.Substring(0, syntax.IndexOf(" of it")).Trim();
var spaceIndex = syntax.IndexOf(" ");
var position = syntax.Substring(0, spaceIndex);
var positionValue = CalculateSyntaxValue(position);
var fraction = syntax.Substring(spaceIndex + 1);
var fractionValue = CalculateSyntaxValue(fraction);
var results = new string[values.Length];
int takeLength, skipCount;
for (int i = 0; i < values.Length; i++)
if (values[i].Length == 0 || values[i].Length % fractionValue != 0)
results[i] = $"ERROR: The string \"{values[i]}\" contains {values[i].Length} characters, which is not divisible into {fractionValue} equal parts.";
takeLength = values[i].Length / fractionValue;
skipCount = takeLength * (positionValue);
private void ValidateParameters(string syntax, string[] values)
if (string.IsNullOrWhiteSpace(syntax))
throw new InvalidSyntaxStringException($"The \"{nameof(syntax)}\" parameter must not be null, empty, or whitespace.");
if ((values?.Length ?? 0) == 0)
throw new InvalidSyntaxStringException($"The \"{nameof(values)}\" parameter must not be null or empty.");
private int CalculateSyntaxValue(string syntax)
if (TryGetTermValue<WholeTerms>(syntax, out var nonCompositeValue)
|| TryGetTermValue<IntermediateTerms>(syntax, out nonCompositeValue))
return nonCompositeValue;
var compositeValue = CalculateCompositeSyntaxValue(syntax, syntax, 0);
private int CalculateCompositeSyntaxValue(string originalSyntax, string decomposedSyntax, int runningTotal)
var result = CalculateIntermediateTermValue(originalSyntax, decomposedSyntax);
if (result.iterationTotal != 0)
return runningTotal += result.iterationTotal;
result = CalculateRootTermValue(originalSyntax, result.iterationTotal, result.iterationDecomp);
result = CalculateMultiplicativeTermSuffixValue(originalSyntax, result.iterationTotal, result.iterationDecomp);
result = CalculateAdditiveTermSuffixValue(result.iterationTotal, result.iterationDecomp);
if (result.iterationDecomp.Length == 0)
var total = runningTotal + result.iterationTotal;
return CalculateCompositeSyntaxValue(originalSyntax, result.iterationDecomp, runningTotal + result.iterationTotal);
private (int iterationTotal, string iterationDecomp) CalculateIntermediateTermValue(string originalSyntax, string iterationDecomp)
var intermediate = Enum.GetNames<IntermediateTerms>().FirstOrDefault(x => iterationDecomp.StartsWith(x));
if (intermediate != null)
TryGetTermValue<IntermediateTerms>(intermediate, out var iterationTotal);
var result = (iterationTotal: iterationTotal, iterationDecomp: iterationDecomp.Substring(intermediate.Length));
if (result.iterationDecomp.Length != 0)
throw new InvalidSyntaxStringException($"The \"syntax\" parameter is malformed: the term \"{originalSyntax}\" is not well formed.");
return (0, iterationDecomp);
private (int iterationTotal, string iterationDecomp) CalculateRootTermValue(string originalSyntax, int iterationTotal, string iterationDecomp)
var root = RootTermNames.FirstOrDefault(x => iterationDecomp.StartsWith(x));
if (root == iterationDecomp)
throw new InvalidSyntaxStringException($"The \"syntax\" parameter is malformed: the term \"{originalSyntax}\" is invalid or not supported.");
TryGetTermValue<RootTerms>(root, out var rootValue);
return (rootValue, iterationDecomp.Substring(root.Length));
return (iterationTotal, iterationDecomp);
private (int iterationTotal, string iterationDecomp) CalculateMultiplicativeTermSuffixValue(string originalSyntax, int iterationTotal, string iterationDecomp)
var multSuffix = MultiplicativeTermSuffixNames.FirstOrDefault(x => iterationDecomp.StartsWith(x));
throw new InvalidSyntaxStringException($"The \"syntax\" parameter is malformed: the term \"{originalSyntax}\" is invalid or not supported.");
TryGetTermValue<MultiplicativeTermSuffixes>(multSuffix, out var factor);
return (iterationTotal *= factor, iterationDecomp.Substring(multSuffix.Length));
return (iterationTotal, iterationDecomp);
private (int iterationTotal, string iterationDecomp) CalculateAdditiveTermSuffixValue(int iterationTotal, string iterationDecomp)
var addSufix = AdditiveTermSuffixNames.FirstOrDefault(x => iterationDecomp.StartsWith(x));
TryGetTermValue<AdditiveTermSuffixes>(addSufix, out var addend);
return (iterationTotal += addend, iterationDecomp.Substring(addSufix.Length));
return (iterationTotal, iterationDecomp);
private bool TryGetTermValue<T>(string syntaxWord, out int numberValue) where T : Enum
if (Enum.TryParse(typeof(T), syntaxWord, out var parsed))
numberValue = (int)parsed;
private enum IntermediateTerms
private string[] _rootTermNames;
private string[] RootTermNames
if (_rootTermNames == null)
_rootTermNames = Enum.GetNames<RootTerms>();
private enum MultiplicativeTermSuffixes
private string[] MultiplicativeTermSuffixNames => Enum.GetNames<MultiplicativeTermSuffixes>();
private enum AdditiveTermSuffixes
private string[] AdditiveTermSuffixNames => Enum.GetNames<AdditiveTermSuffixes>();
public abstract class ParserException : Exception
public ParserException(string message) : base(message) { }
public class InvalidSyntaxStringException : ParserException
public InvalidSyntaxStringException(string message) : base(message) { }
public class InvalidWordsArrayException : ParserException
public InvalidWordsArrayException(string message) : base(message) { }