Skip to content

Instantly share code, notes, and snippets.

@Geogboe
Created January 12, 2018 17:22
Show Gist options
  • Save Geogboe/2dcfaa1f06ce35219b78c58f34638ef8 to your computer and use it in GitHub Desktop.
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
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