PowerShell 7正则提取文件名国家列表失效及Regexr匹配异常求助
从文件名中提取国家名称的正则修正方案
问题背景
需要从文件名列表中提取括号内的国家名称(支持逗号分隔的多个国家),原正则在PowerShell 7中出现匹配错误,例如将(USA) (Proto)中的USA) (Proto全部纳入匹配结果;同时在Regexr工具中处理Mein Weg (USA, Germany) (En)时,会出现跨行匹配的异常。
原使用的正则表达式:
$regex = "^[^\(]* \(([\b(USA|Japan|Europe|Germany|Canada)\b,\s]*)\).*$"
示例文件名列表:
3-D Genesis (USA) (Proto) Wallaby!! - Usagi no Kuni no Kangaroo Race (Japan) (Wii U Virtual Console) UWOL - Quest for Money (World) (v1.1) (Aftermarket) (Unl) Super Star Soldier (USA, Europe) (Wii U Virtual Console) Soldier Blade (USA, Europe) (Wii U Virtual Console) Mein Weg (USA, Germany) (En) Challenge (Canada)
原正则的错误匹配结果:
Name Value ---- ----- 1 USA) (Proto 0 3-D Genesis (USA) (Proto)
原正则的问题分析
- 词边界误用:
\b被放在字符组内,无法起到单词边界的限制作用,反而会被解析为普通字符,导致无法精准匹配国家名称的边界。 - 字符组逻辑错误:
[\b(USA|Japan|Europe|Germany|Canada)\b,\s]*是字符组而非分支匹配组,|会被当作普通字符处理,意味着会匹配括号、国家名称的单个字符、逗号、空格的任意组合,自然会把后续的) (Proto这类无关内容包含进来。 - 跨行匹配隐患:
.*在多行模式下会匹配换行符,导致处理末尾行时会跨到下一行内容。
修正后的正则与实现代码
基础匹配正则(PowerShell 7)
$regex = "^[^(]* \((?:(USA|Japan|Europe|Germany|Canada)(?:, )?)+\).*$"
正则逻辑拆解
^[^(]*:匹配文件名开头到第一个((空格加左括号)之前的主体内容\(:匹配左括号(?:(USA|Japan|Europe|Germany|Canada)(?:, )?)+:非捕获组,用于匹配一个或多个国家名称:(USA|Japan|Europe|Germany|Canada):捕获指定范围内的国家名称(?:, )?:非捕获组,处理单个国家或多个国家之间的,分隔符
\):匹配右括号.*$:匹配括号后的剩余内容,确保整行匹配
提取所有匹配国家的完整代码
如果需要提取单个文件名中的所有国家(包括多个逗号分隔的情况),可以使用[regex]::Matches()来获取所有匹配项:
# 定义目标国家列表 $targetCountries = "USA", "Japan", "Europe", "Germany", "Canada" # 构建正则模式 $regexPattern = "\b(" + ($targetCountries -join "|") + ")\b" # 示例文件名列表 $fileNameList = @( "3-D Genesis (USA) (Proto)", "Wallaby!! - Usagi no Kuni no Kangaroo Race (Japan) (Wii U Virtual Console)", "UWOL - Quest for Money (World) (v1.1) (Aftermarket) (Unl)", "Super Star Soldier (USA, Europe) (Wii U Virtual Console)", "Soldier Blade (USA, Europe) (Wii U Virtual Console)", "Mein Weg (USA, Germany) (En)", "Challenge (Canada)" ) # 遍历处理每个文件名 foreach ($name in $fileNameList) { $matches = [regex]::Matches($name, $regexPattern) $extractedCountries = $matches.Value -join ", " if ($extractedCountries) { Write-Host "文件名: $name`n提取的国家: $extractedCountries`n" } else { Write-Host "文件名: $name`n未匹配到指定国家`n" } }
验证结果
运行上述代码后,会得到正确的提取结果:
3-D Genesis (USA) (Proto)→ 提取的国家: USAWallaby!! - Usagi no Kuni no Kangaroo Race (Japan) (Wii U Virtual Console)→ 提取的国家: JapanUWOL - Quest for Money (World) (v1.1) (Aftermarket) (Unl)→ 未匹配到指定国家Super Star Soldier (USA, Europe) (Wii U Virtual Console)→ 提取的国家: USA, EuropeSoldier Blade (USA, Europe) (Wii U Virtual Console)→ 提取的国家: USA, EuropeMein Weg (USA, Germany) (En)→ 提取的国家: USA, GermanyChallenge (Canada)→ 提取的国家: Canada
补充注意事项
- PowerShell的
-match运算符默认是单行模式,.*不会匹配换行符,可避免跨行匹配问题;如果使用[regex]::Matches(),可指定[System.Text.RegularExpressions.RegexOptions]::Singleline确保行为一致。 - 使用
\b单词边界可以避免误匹配包含目标国家名称的其他字符串(比如不会把USAA误识别为USA)。
内容的提问来源于stack exchange,提问作者thomasb
相关产品推荐
相关产品推荐

