PowerShell实现CSV文件应用名称模糊匹配的问题求助
解决CSV文件中应用名称的跨格式匹配问题
原脚本的核心错误
你的脚本返回0匹配的原因有几个关键问题:
- 标志位初始化位置错误:
$allPartsMatch在循环外初始化,一旦某次匹配失败设为$false后,后续所有循环都会沿用这个值,永远不会触发匹配成功的逻辑。 - 数组匹配逻辑错误:
$ProductSplit -notcontains $ApplicationSplit是在检查$ProductSplit数组是否包含整个$ApplicationSplit数组,而不是检查后者的元素是否存在于前者中,完全不符合你的匹配需求。 - 匹配逻辑方向错误:你需要的是识别两个名称的核心重叠部分,而不是要求一个名称的所有片段都包含在另一个里——比如你的例子中,"Continuous MUI"和"v2022.002.20191"是各自独有的片段,原逻辑会直接判定不匹配。
可行的解决方案
针对应用名称的格式差异,推荐两种高效的匹配思路:
思路1:基于核心关键词的精准匹配
先定义每个应用的核心标识规则(比如提取版本号、后缀前的核心名称),再用这些核心标识做匹配。
示例脚本
# 导入CSV文件 $Products01 = Import-CSV 'C:\Temp\ProductsList01.csv' -Delimiter ";" $Products02 = Import-CSV 'C:\Temp\ProductList02.csv' -Delimiter ";" # 存储匹配结果的数组(用数组比哈希表更适合后续导出CSV) $MatchingApps = @() # 遍历第一个CSV的每个应用 foreach ($prod in $Products01) { $prodName = $prod.Product # 提取核心名称:去掉版本号、后缀(比如Continuous MUI这类) # 正则规则:匹配到第一个数字开头的部分或特定后缀前的内容 $prodCore = [regex]::Match($prodName, "^(.*?)(?=\s+v?\d|Continuous|MUI)").Value.Trim() # 遍历第二个CSV找匹配 foreach ($app in $Products02) { $appName = $app.Column1 $appCore = [regex]::Match($appName, "^(.*?)(?=\s+v?\d|Continuous|MUI)").Value.Trim() # 核心名称一致则记录匹配 if ($prodCore -eq $appCore) { $MatchingApps += [PSCustomObject]@{ Product01 = $prodName Product02 = $appName CoreName = $prodCore } # 找到匹配后跳出内层循环,避免重复匹配(如果一个应用对应多个的话可以去掉) break } } } # 输出结果到控制台 $MatchingApps | Format-Table -AutoSize # 导出匹配结果到CSV(可选) $MatchingApps | Export-CSV 'C:\Temp\MatchedApps.csv' -Delimiter ";" -NoTypeInformation
思路2:基于字符串相似度的模糊匹配
如果核心标识规则不好定义,可以用字符串相似度算法(比如Levenshtein距离)来匹配相似名称,适合格式差异较大但名称接近的场景。
示例脚本(包含相似度计算函数)
# 计算Levenshtein距离(字符串相似度)的函数 function Get-StringSimilarity { param( [string]$String1, [string]$String2 ) $len1 = $String1.Length $len2 = $String2.Length $matrix = New-Object 'int[,]' ($len1 + 1), ($len2 + 1) for ($i = 0; $i -le $len1; $i++) { $matrix[$i, 0] = $i } for ($j = 0; $j -le $len2; $j++) { $matrix[0, $j] = $j } for ($i = 1; $i -le $len1; $i++) { for ($j = 1; $j -le $len2; $j++) { $cost = if ($String1[$i-1] -eq $String2[$j-1]) { 0 } else { 1 } $matrix[$i, $j] = [math]::Min( [math]::Min($matrix[$i-1, $j] + 1, $matrix[$i, $j-1] + 1), $matrix[$i-1, $j-1] + $cost ) } } # 返回相似度(1 - 距离/最长字符串长度) $maxLen = [math]::Max($len1, $len2) if ($maxLen -eq 0) { return 1.0 } return 1.0 - ($matrix[$len1, $len2] / $maxLen) } # 导入CSV $Products01 = Import-CSV 'C:\Temp\ProductsList01.csv' -Delimiter ";" $Products02 = Import-CSV 'C:\Temp\ProductList02.csv' -Delimiter ";" $MatchingApps = @() $similarityThreshold = 0.7 # 相似度阈值,可调整 foreach ($prod in $Products01) { $prodName = $prod.Product $bestMatch = $null $highestSimilarity = 0 foreach ($app in $Products02) { $appName = $app.Column1 $similarity = Get-StringSimilarity $prodName $appName if ($similarity -ge $similarityThreshold -and $similarity -gt $highestSimilarity) { $highestSimilarity = $similarity $bestMatch = $appName } } if ($bestMatch) { $MatchingApps += [PSCustomObject]@{ Product01 = $prodName Product02 = $bestMatch Similarity = [math]::Round($highestSimilarity, 2) } } } # 输出结果 $MatchingApps | Format-Table -AutoSize
关键优化点说明
- 用
PSCustomObject存储结果,比哈希表更灵活,方便后续导出CSV或格式化输出。 - 核心匹配思路优先:对于应用名称,精准提取核心标识比模糊匹配更可靠,建议先整理出常见的后缀/版本前缀规则(比如
v\d、Continuous、MUI、x64等),优化正则表达式。 - 循环内的提前跳出:找到匹配后跳出内层循环,减少不必要的计算,提升处理效率(适合数百条数据的场景)。
内容的提问来源于stack exchange,提问作者Fred Eric S
相关产品推荐
相关产品推荐

