static void SetAddress(StagedPerson person, string fullAddress, string address1, string address2, ref string company) { // If we already parsed an address, skip all of the work. // We check this here to make sure the address fields are // still added to usedValues to avoid duplicate comments. if (person.Address != null) { return; } if (fullAddress == null) { company = null; person.Address = ""; return; } fullAddress = fullAddress.Replace(",", ", ").NormalizeSpaces().Trim(); address1 = address1?.Trim().NormalizeSpaces(); address2 = address2?.Trim().NormalizeSpaces(); if (address2 == null || addressPartDetector.IsMatch(address2 ?? "") || address1.StartsWith("PO Box")) { // If the second field is a continuation of the first, combine them. person.Address = (address1 + " " + address2).Trim(); company = null; } else { // Otherwise, assume it's 'Company Address'. if (!char.IsNumber(address2[0])) { throw new InvalidOperationException($"Weird address for {person.FullName}: '{address1}', '{address2}' ({fullAddress})"); } company = address1; person.Address = address2; } var firstParts = (address1 + " " + address2).Trim(); if (!fullAddress.StartsWith(firstParts)) { throw new InvalidOperationException($"Unrecognized address format for {person.FullName}: '{fullAddress}' expected to start with '{firstParts}'"); } var parsed = addressParser.Match(fullAddress.Substring(firstParts.Length).Trim()); person.City = parsed.Groups[1].Value; person.State = UsStates.Abbreviate(parsed.Groups[2].Value.Replace(".", "")); person.Zip = parsed.Groups[3].Value; }
static IEnumerable <Person> Fuzzy(IImportingPerson source) { IEnumerable <Person> candidates = AppFramework.Table <Person>().Rows; // Filter by each field, but only if that field has any matches. if (!string.IsNullOrEmpty(source.Address)) { var sourceAddress = AddressInfo.Parse(source.Address); var sourceState = UsStates.Abbreviate(source.State); candidates = candidates.Where(p => IsMatch(p.Zip, source.Zip) && IsMatch(p.State, sourceState) && IsMatch(p.City, source.City) && AddressInfo.Parse(p.Address) == sourceAddress) .DefaultIfEmpty(candidates); } candidates = candidates.Where(p => p.LastName.Equals(source.LastName, StringComparison.CurrentCultureIgnoreCase)) .DefaultIfEmpty(candidates); if (!string.IsNullOrWhiteSpace(source.LastName)) { candidates = candidates.LevenshteinDistanceOf(p => p.LastName).ComparedTo(source.LastName) .BestMatches() .DefaultIfEmpty(candidates); } // Match the imported first name against either HisName or HerName. if (!string.IsNullOrWhiteSpace(source.FirstName)) { candidates = candidates.LevenshteinDistanceOf(p => p.HisName).ComparedTo(source.FirstName) .Union(candidates.LevenshteinDistanceOf(p => p.HerName).ComparedTo(source.FirstName)) .BestMatches() .Distinct() .DefaultIfEmpty(candidates); } // If none of the matches found anything, give up. if (candidates == AppFramework.Table <Person>().Rows) { return(Enumerable.Empty <Person>()); } return(candidates); }