Created
January 12, 2018 17:22
-
-
Save Geogboe/2dcfaa1f06ce35219b78c58f34638ef8 to your computer and use it in GitHub Desktop.
PowerShell function which parses a list of strings and returns the string most closely matching the provided string
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Invoke-StringMatch { | |
<# | |
.SYNOPSIS | |
Parses a list of strings and return the string most closely matching the provided string | |
.DESCRIPTION | |
Function will take a providded search string, remove special characters and create an array | |
out of all the words in the string. | |
Then, it will loop through this array and check to see if a given word is found in any of | |
the string in the provided string list. The input list will then be trimmed down to only | |
include string that contain that word. | |
This process will continue with all the words until we've narrowed the match down to just | |
one results. | |
If multiple results are still found at the end, we look at the string and illiminate any that | |
contain words that are NOT found in the original search string, until we get down to one match. | |
.NOTES | |
- I guess technically you could just use regex rather than this function but that's super complicated | |
- Future Features: | |
- I'd love to add more complex matching using parameters | |
- Include support for matching special characters | |
#> | |
[CmdletBinding()] | |
param ( | |
# The input string to match against | |
[string] | |
$InputString, | |
# A list of string to iterate through | |
[string[]] | |
$StringList | |
) | |
process { | |
# Break up the input string into a list of words | |
$Words = $InputString -split " " | |
$WordObjects = @() | |
foreach ( $Word in $Words ) { | |
$WordObject = [pscustomobject]@{ | |
Word = $Word | |
Matches = @() | |
} | |
# Find all matches in list that contain that word | |
Write-Verbose ( "Searching with word: $Word" ) | |
foreach ( $String in $StringList ) { | |
if ( $String -imatch "$Word" ) { | |
Write-Debug ( "Matching string: $String" ) | |
$WordObject.Matches += $String | |
} | |
} | |
# Narrow down the list for the next word | |
$StringList = $WordObject.Matches | |
$WordObjects += $WordObject | |
} | |
# Check the final word to see if more than 1 match was found | |
$FinalMatches = $WordObjects[-1].Matches | |
if ( $FinalMatches.Count -gt 1 ) { | |
# Print the matches for debugging | |
$FinalMatches.Foreach( { Write-Verbose "Match: $_"}) | |
Write-Verbose ( | |
"For the given search: {0} total matches were found. Attempting to narrow down search by excluded results with additional words." -f | |
$FinalMatches.Count | |
) | |
# List to hold more specific matches | |
$FilterMatches = @() | |
# try to narrow down the search by excluding results that contain words not in the original query | |
$MatchesCount = $FinalMatches.Count | |
:ParentForEach foreach ( $Match in $FinalMatches ) { | |
# Remove special characters from the string | |
$CleanString = $Match -replace "\)" -replace "\(" -replace "," | |
Write-Verbose ( | |
"Removed special characters from match: {0} to make: {1}" -f | |
$Match, $CleanString | |
) | |
# Break up the words in the string into an array | |
$WordsInMatch = $CleanString -split " " | |
foreach ( $Word in $WordsInMatch ) { | |
# Stop if we get down to 1 match | |
if ( $MatchesCount -le 1 ) { | |
Write-Verbose ( | |
"Matches have been narrowed down to one result: {0}" -f | |
$Match | |
) | |
$FilterMatches += $Match | |
break ParentForEach | |
} | |
elseif ( $InputString -inotmatch "$Word") { | |
Write-Verbose ( | |
"Word: {0} was NOT found in original search string: {1}. Match: {2} excluded" -f | |
$Word, $InputString, $Match | |
) | |
$MatchesCount -= 1 # reduce the count of matches so that when we get to the final one we break out of this | |
Continue ParentForEach # Continue the from the top level loop | |
} | |
} | |
# Add match that hasn't been elliminated to a new list | |
$FilterMatches += $Match | |
} | |
if ( $FilterMatches.Count -gt 1 ) { | |
# throw an error if there is still more than one match | |
Write-Verbose ( | |
"For the given search: {0} multiple matches were found. Please clarify the search." -f | |
$FinalMatches.Count | |
) -WarningAction Continue | |
throw "Multiple matches found" | |
} | |
# Copy these over and continue remaining test | |
$FinalMatches = $FilterMatches | |
} | |
if ( $FinalMatches.Count -lt 1 ) { | |
Write-Warning ( | |
"For the given search: {0} NO matches were found. Please clarify the search" -f | |
$FinalMatches.Count | |
) -WarningAction Continue | |
throw "No matches found" | |
} | |
else { | |
return $FinalMatches | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment