You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

正则表达式能否捕获文本块中的多个相似模式?PowerShell下多匹配结果提取异常问题咨询

解决PowerShell正则捕获重复命名组只保留最后一项的问题

问题场景

我最近需要从一批游戏音效配置文本里提取数据,文本格式是这样的:

soundeffect = { name = event_ship_explosion sounds = { sound = event_ship_explosion } volume = 0.2 max_audible = 1 max_audible_behaviour = fail }
soundeffect = { name = event_ship_bridge sounds = { sound = event_ship_bridge sound = event_ship_bridge_02 sound = event_ship_bridge_03 } volume = 0.3 max_audible = 1 max_audible_behaviour = fail }

我的需求很明确:每个soundeffect块里,把name对应的值和所有sound条目对应的值关联起来,比如第二个块要得到event_ship_bridge对应三个sound值的集合。

一开始我写了这么个正则:

name\s*=\s*(?<Group>\w+)\s*sounds\s*=\s*{\s*(?>\s*sound\s*=\s*(?<Sound>\w+)\s*)+}

在测试工具上明明能看到Sound组有3个匹配结果,但放到PowerShell里用Select-String跑的时候,却只保留了最后一个sound值,而且感觉-AllMatches参数没生效,结果完全不符合预期。

问题根源

后来我才搞明白:PowerShell的Select-String在处理命名捕获组时,默认只会保留该组最后一次匹配的内容,不会自动收集所有重复匹配的项。而且我的正则把整个sounds块作为一个整体匹配,内部的Sound组重复匹配不会被单独记录下来,自然拿不到所有结果。

两种可行解决方案

方案一:分块处理(简单易理解)

先把每个soundeffect块单独匹配出来,再逐个块提取name和所有sound值,逻辑清晰不容易出错:

# 第一步:匹配所有完整的soundeffect块
$blockRegex = 'soundeffect\s*=\s*{[^}]+}'
$blocks = $Text | Select-String -Pattern $blockRegex -AllMatches | ForEach-Object { $_.Matches.Value }

# 第二步:逐个处理块,提取目标数据
$result = $blocks | ForEach-Object {
    $currentBlock = $_
    # 提取name的值
    $groupName = ($currentBlock | Select-String -Pattern 'name\s*=\s*(\w+)' -AllMatches).Matches.Groups[1].Value
    # 提取所有sound的值
    $soundList = ($currentBlock | Select-String -Pattern 'sound\s*=\s*(\w+)' -AllMatches).Matches.Groups[1].Value
    # 返回自定义对象
    [PSCustomObject]@{
        Group = $groupName
        Sound = $soundList
    }
}

# 查看结果
$result

运行后得到的结果完全符合预期,第二个块的输出是:

Group               Sound
-----               -----
event_ship_bridge   {event_ship_bridge, event_ship_bridge_02, event_ship_bridge_03}

方案二:借助.NET正则的Captures属性(进阶)

如果你想用单个正则实现,可以直接调用.NET的[regex]类,它的Captures属性会记录命名组的所有匹配项,而不是只保留最后一个:

# 定义正则,(?s)开启单行模式,适配可能有换行的配置文本
$regex = [regex]'(?s)name\s*=\s*(?<Group>\w+)\s*sounds\s*=\s*{\s*(?:\s*sound\s*=\s*(?<Sound>\w+)\s*)+}'

# 执行匹配
$allMatches = $regex.Matches($Text)

# 处理匹配结果,提取所有捕获项
$result = $allMatches | ForEach-Object {
    $groupName = $_.Groups['Group'].Value
    # 通过Captures获取Sound组的所有匹配值
    $soundList = $_.Groups['Sound'].Captures | ForEach-Object { $_.Value }
    [PSCustomObject]@{
        Group = $groupName
        Sound = $soundList
    }
}

# 查看结果
$result

这个方案更简洁,适合熟悉.NET正则细节的场景,同样能得到完整的关联数据。

后续处理

得到这个对象数组后,你可以直接用ConvertFrom-Text或者其他工具进一步处理,比如导出为CSV、JSON格式,或者直接在PowerShell里进行筛选、统计操作。

内容的提问来源于stack exchange,提问作者Tuttu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 12:57:45