Home > database >  Matching list of words but not when found inside longer words
Matching list of words but not when found inside longer words

Time:07-13

I have a list of keywords (sometimes with non-alphanumeric characters) that I’d like to find in a list of files. I can do that with the code below, but I want to avoid matching keywords if they are found inside another word, e.g.:

Keywords.csv:

Keywords
Lo.rem <-- Match if not prefixed by nor suffixed with a letter
is <-- Same
simply) <-- Match if not prefixed by a letter
printing. <-- Same
(text <-- Match if not suffixed with a letter
-and <-- Same

Files.csv:

Files
C:\AFolder\aFile.txt
C:\AFolder\AnotherFolder\anotherFile.txt
C:\AFolder\anotherFile2.txt

Here's my code so far if useful:

$keywords = (((Import-Csv "C:\Keywords.csv" | Where Keywords).Keywords)-replace '[[ *?()\\.]','\$&') #Import list of keywords to search for
$paths = ((Import-Csv "C:\Files.csv" | Where Files).Files) #Import list of files to look for matching keywords
$count = 0

ForEach ($path in $paths) {
$file = [System.IO.FileInfo]$path
Add-Content -Path "C:\Matches\$($count)__$($file.BaseName)_Matches.txt" -Value $file.FullName #Create a file in C:\Matches and insert the path of the file being searched

$hash = @{}
Get-Content $file |
  Select-String -Pattern $keywords -AllMatches |
  Foreach {$_.Matches.Value} | 
%{if($hash.$_ -eq $null) { $_ }; $hash.$_ = 1} | #I don't remember what this does, probably fixes error messages I was getting
Out-File -FilePath "C:\Matches\$($count)__$($file.BaseName)_Matches.txt" -Append -Encoding UTF8 #Appends keywords that were found to the file created
$count = $count  1
}

I’ve tried playing with regex negative lookahead/lookbehind but did not get anywhere, especially since I’m a beginner in PowerShell, e.g.:

Select-String -Pattern "(?<![A-Za-z])$($keywords)(?![A-Za-z])" -AllMatches 

Any suggestions? Much appreciated

CodePudding user response:

This will escape any regex reserved characters in your keyword list, and join them with | to specify the OR condition, and then wrap them in parenthesis.

"(?<![A-Za-z])($(($keywords|%{[regex]::escape($_)}) -join '|'))(?![A-Za-z])"

That would be consumed as something like this:

"(?<![A-Za-z])(Lo\.rem|is|simply\)|printing\.|\(text|-and)(?![A-Za-z])"
  • Related