首页 > 解决方案 > Powershell 中的高级模式匹配

问题描述

希望你能帮我做点什么。感谢@mklement0,我得到了一个很棒的脚本,它与按字母顺序排列的单词的最基本、初始模式相匹配。但是缺少的是全文搜索和选择。当前脚本的示例,其中包含 Words.txt 文件中的几个单词的小样本:

App
Apple
Apply
Sword
Swords
Word
Words

变成:

App
Sword
Word

这很棒,因为它确实缩小到每行的基本模式!然而,它逐行运行的结果仍然有一个可以进一步缩小范围的模式,即“Word”(大写不重要),所以理想情况下输出应该是:

App
Word

并且“剑”被删除,因为它属于更基本的以“单词”为前缀的模式。

您对如何实现这一目标有什么建议吗?请记住,这将是一个大约 250k 单词的字典列表,所以我不会提前知道我在寻找什么

代码(来自相关帖子,仅处理前缀匹配):

$outFile = [IO.File]::CreateText("C:\Temp\Results.txt")   # Output File Location
$prefix = ''                   # initialize the prefix pattern

foreach ($line in [IO.File]::ReadLines('C:\Temp\Words.txt')) # Input File name.
 {

  if ($line -like $prefix) 
    { 
    continue                   # same prefix, skip
    }

  $line                        # Visual output of new unique prefix
  $prefix = "$line*"           # Saves new prefix pattern
  $outFile.writeline($line)    # Output file write to configured location
}

标签: regexpowershellpattern-matching

解决方案


您可以尝试两步法:

  • 步骤 1:在按字母顺序排序的单词列表中查找唯一前缀列表。这是通过顺序读取行来完成的,因此只需要您将唯一的前缀作为一个整体保存在内存中。

  • 第 2 步:按长度顺序对生成的前缀进行排序并对其进行迭代,在每次迭代中检查手头的单词是否已经在结果列表中由它的子字符串表示。

    • 结果列表一开始是空的,只要手头的单词在结果列表中没有子字符串,它就会被附加到列表中。

    • 结果列表被实现为带有交替 ( ) 的正则表达式|,以便在单个操作中匹配所有已经找到的唯一单词。

你必须看看性能是否足够好;为了获得最佳性能,尽可能直接使用 .NET 类型。

# Read the input file and build the list of unique prefixes, assuming
# alphabetical sorting.
$inFilePath = 'C:\Temp\Words.txt' # Be sure to use a full path.
$uniquePrefixWords = 
  foreach ($word in [IO.File]::ReadLines($inFilePath)) {
    if ($word -like $prefix) { continue }
    $word
    $prefix = "$word*"
  }

# Sort the prefixes by length in ascending order (shorter ones first).
# Note: This is a more time- and space-efficient alternative to:
#    $uniquePrefixWords = $uniquePrefixWords | Sort-Object -Property Length
[Array]::Sort($uniquePrefixWords.ForEach('Length'), $uniquePrefixWords)

# Build the result lists of unique shortest words with the help of a regex.
# Skip later - and therefore longer - words, if they are already represented
# in the result list of word by a substring.
$regexUniqueWords = ''; $first = $true
foreach ($word in $uniquePrefixWords) {
  if ($first) { # first word
    $regexUniqueWords = $word
    $first = $false
  } elseif ($word -notmatch $regexUniqueWords) {
    # New unique word found: add it to the regex as an alternation (|)
    $regexUniqueWords += '|' + $word
  }
}

# The regex now contains all unique words, separated by "|".
# Split it into an array of individual words, sort the array again...
$resultWords = $regexUniqueWords.Split('|')
[Array]::Sort($resultWords)

# ... and write it to the output file.
$outFilePath = 'C:\Temp\Results.txt' # Be sure to use a full path.
[IO.File]::WriteAllLines($outFilePath, $resultWords)

推荐阅读