/// <summary> /// Processes <paramref name="rawAddressData"/> with the RegEx set up in <typeparamref name="TOutputFormat"/>. /// </summary> /// <remarks>The input and output manipulation functions will also be processed.</remarks> /// <param name="rawAddressData">The input string.</param> /// <exception cref="ArgumentNullException"><see cref="IOutputFormat.MatchingRegex"/> must be set up correctly in the generic class.</exception> /// <exception cref="MissingMemberException">Should contain at least one <see cref="RegexGroupAttribute"/>.</exception> /// <example> /// This sample shows how to call the <see cref="AddressSeparationProcessor{TOutputFormat}"/> constructor. /// <code> /// class TestClass /// { /// static int Main() /// { /// var processor = new AddressSeparationProcessor{GermanSimpleOutputFormat}(); /// var result = processor.Process('Teststraße 123a'); /// var address = result.ResolvedAddress; /// /// Console.WriteLine($"Name is {address.StreetName} with number {address.HouseNumber} and affix {address.HouseNumberAffix}"); /// } /// } /// </code> /// </example> /// <returns>The resolved address along with info about the processing.</returns> public OutputResult <TOutputFormat> Process(string rawAddressData) { // sanity check var outputFormatInstance = Activator.CreateInstance(typeof(TOutputFormat)) as IOutputFormat; _ = outputFormatInstance.MatchingRegex ?? throw new ArgumentNullException(nameof(outputFormatInstance.MatchingRegex)); Options = Options ?? new DefaultProcessingOptions(); // create output instance var outputResult = new OutputResult <TOutputFormat>(rawAddressData); // return empty result, if input is empty if (String.IsNullOrWhiteSpace(rawAddressData)) { return(outputResult); } // call user defined input functions rawAddressData = this.ProcessInputManipulationQueue(rawAddressData); // get all properties w/ RegexGroupAttribute and throw exception if there is none var propertyRegexGroupCollection = OutputFormatHelper.GetPropertyRegexGroups(typeof(TOutputFormat)); if (Options.ThrowIfNoRegexGroupPropertyProvided && propertyRegexGroupCollection.Any() == false) { throw new MissingMemberException($"Class {typeof(TOutputFormat).Name} has no property members with {nameof(RegexGroupAttribute)}."); } // assign to Regex bindings var match = outputFormatInstance.MatchingRegex.Match(rawAddressData); if (match.Success) { foreach (var prop in propertyRegexGroupCollection) { // get first matching group value; null, if no group is matching string valueOfGroup = null; do { // get groups one by one and manipulate if necessary var currentGroup = prop.RegexGroupCollection.Dequeue(); valueOfGroup = match.Groups[currentGroup.RegexGroupIndex]?.Value; valueOfGroup = this.ProcessOutputManipulation(valueOfGroup, currentGroup); // set value to instance member this.SetPropertyValue(prop.Property, outputResult.GetInstance(), valueOfGroup); } while (prop.RegexGroupCollection.Count > 0 && String.IsNullOrWhiteSpace(valueOfGroup)); } // set success outputResult.AddressHasBeenResolved = true; } // return filled instance return(outputResult); }