加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Powershell:用变量替换正则表达式命名组

发布时间:2020-12-14 06:00:12 所属栏目:百科 来源:网络整理
导读:假设我有一个如下所示的正则表达式,但我将它从一个文件加载到一个变量$ regex中,所以在设计时不知道它的内容是什么,但在运行时我发现它包含“version1”,“version2”,“version3”和“version4”命名组: "Version (?version1d),(?version2d),(?version3
假设我有一个如下所示的正则表达式,但我将它从一个文件加载到一个变量$ regex中,所以在设计时不知道它的内容是什么,但在运行时我发现它包含“version1”,“version2”,“version3”和“version4”命名组:

"Version (?<version1>d),(?<version2>d),(?<version3>d),(?<version4>d)"

……我有这些变量:

$version1 = "3"
$version2 = "2"
$version3 = "1"
$version4 = "0"

…我在文件中遇到以下字符串:

Version 7,7,0

…存储在变量$input中,因此($input -match $regex)的计算结果为$true.

如果我不知道它们出现在$regex中的顺序,我怎么能用字符串$input中的$regex替换$version1,$version2,$version3,$version4的值中的命名组(我只知道$正则表达式包括这些命名组)?

我找不到任何描述使用组名作为匹配索引用变量值替换命名组的语法的引用 – 这是否支持?

编辑:
为了澄清 – 目标是在任何类型的文本文件中替换模板化版本字符串,其中给定文件中的版本字符串需要替换可变数量的版本字段(可以是2,3或全部4个字段).例如,文件中的文本可能看起来像这些中的任何一个(但不限于这些):

#define SOME_MACRO(4,1,0)

Version "1.2.3.4"

SomeStruct vs = { 99,99,99 }

用户可以指定文件集和正则表达式以匹配包含字段的行,最初的想法是命名组将捕获各个字段.该实用程序具有应在文件中替换的各个版本字段值,但必须保留将包含替换的行的原始格式,并仅替换所请求的字段.

EDIT 2:
我想我可以根据每个匹配的位置和范围得到我需要的子串计算结果,但是希望Powershell的替换操作能够为我节省一些工作.

编辑-3:
因此,正如Ansgar在下面正确而简洁地描述的那样,没有办法(仅使用原始输入字符串,正则表达式,您只知道命名组,以及产生的匹配)来使用“-replace”操作(或其他正则表达式操作)执行命名组的捕获的替换,同时保留原始字符串的其余部分.对于这个问题,如果有人好奇,我最终使用下面的解决方案. YMMV,其他解决方案可行.非常感谢Ansgar提供的反馈和选择.

在以下代码块中:

> $input是要在其上执行替换的一行文本
> $regex是一个正则表达式(类型为[string])从已验证包含至少一个受支持的命名组的文件中读取
> $regexToGroupName是一个哈希表,它将正则表达式字符串映射到根据[regex] :: GetGroupNames()返回的数组的顺序排序的组名称数组,这些数组匹配它们出现的从左到右的顺序在表达中
> $groupNameToVersionNumber是一个哈希表,用于将组名映射到版本号.

$regex中命名组的约束只是(我认为)命名组中的表达式不能嵌套,并且在输入字符串中最多应匹配一次.

# This will give us the index and extent of each substring
# that we will be replacing (the parts that we will not keep)
$matchResults = ([regex]$regex).match($input)

# This will hold substrings from $input that were not captured
# by any of the supported named groups,as well as the replacement
# version strings,properly ordered,but will omit substrings captured
# by the named groups
$lineParts = @()
$startingIndex = 0
foreach ($groupName in $regexToGroupName.$regex)
{
    # Excise the substring leading up to the match for this group...
    $lineParts = $lineParts + $input.Substring($startingIndex,$matchResults.groups[$groupName].Index - $startingIndex)

    # Instead of the matched substring,we'll use the substitution
    $lineParts = $lineParts + $groupNameToVersionNumber.$groupName

    # Set the starting index of the next substring that we will keep...
    $startingIndex = $matchResults.groups[$groupName].Index + $matchResults.groups[$groupName].Length
}

# Keep the end of the original string (if there's anything left)
$lineParts = $lineParts + $input.Substring($startingIndex,$input.Length - $startingIndex)

$newLine = ""
foreach ($part in $lineParts)
{
   $newLine = $newLine + $part
}
$input= $newLine

解决方法

正则表达式不起作用,所以你不能.不是直接的,也就是说.您可以做什么(除了使用更合适的正则表达式对要保留的部分进行分组)是提取版本字符串,然后在第二步中用新版本字符串替换该子字符串:

$oldver = $input -replace $regexp,'$1,$2,$3,$4'
$newver = $input -replace $oldver,"$Version1,$Version2,$Version3,$Version4"

编辑:

如果您甚至不知道结构,则必须从正则表达式中提取该结构.

$version = @($version1,$version4)
$input -match $regexp
$oldver = $regexp
$newver = $regexp
for ($i = 1; $i -le 4; $i++) {
  $oldver = $oldver -replace "(?<version$i>d)",$matches["version$i"]
  $newver = $newver -replace "(?<version$i>d)",$version[$i-1]
}
$input -replace $oldver,$newver

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读