在PowerShell替换循环中添加捕获组值

时间:2018-09-16 06:58:41

标签: regex powershell

需要将多个文本文件中的字符串替换为相同的字符串,但捕获组2替换为自身和捕获组4的总和。

字符串:Total amount $11.39 | Change $0.21
所需结果:Total amount $11.60 | Change $0.21

我尝试了几种方法。这是我的最后一次尝试,似乎没有错误,但对字符串没有任何更改。

$Originalfolder = "$ENV:userprofile\Documents\folder\"
$Originalfiles = Get-ChildItem -Path "$Originalfolder\*"

$RegexPattern = '\b(Total\s\amount\s\$)(\d?\d?\d?\d?\d\.?\d?\d?)(\s\|\sChange\s\$)(\d?\d?\d\.?\d?\d?)\b'
$Substitution = {
    Param($Match)
    $Result = $GP1 + $Sumtotal + $GP3 + $Change
    $GP1 = $Match.Groups[1].Value
    $Total = $Match.Groups[2].Value
    $GP3 = $Match.Groups[3].Value
    $Change = $Match.Groups[4].Value
    $Sumtotal = ($Total + $Change)
    return [string]$Result
}

foreach ($file in $Originalfiles) {
    $Lines = Get-Content $file.FullName
    $Lines | ForEach-Object {
        [Regex]::Replace($_, $RegexPattern, $Substitution)
    } | Set-Content $file.FullName
}

2 个答案:

答案 0 :(得分:0)

这是我的操作方式:这是从较大的脚本中抽出的,该脚本会定期扫描目录中的文件,然后执行类似的操作,并且我已迅速将变量更改为混淆状态,因此请大声喊叫工作,明天我会详细介绍。

它也需要备份每个文件,并在重命名之前使用临时副本。

请注意,它还会发送电子邮件警报(末尾代码),以说明是否进行了任何处理-这是因为它旨在按原计划中的计划任务运行

$backupDir = "$pwd\backup"
$stringToReplace = "."
$newString = "."

$files = @(Get-ChildItem $directoryOfFiles)

$intFiles = $files.count

$tmpExt = ".tmpDataCorrection"
$DataCorrectionAppend = ".DataprocessBackup"

    foreach ($file in $files) {
    $content = Get-Content -Path ( $directoryOfFiles + $file )
    # Check whether there are any instances of the string
    If (!($content -match $stringToReplace)) { 
        # Do nothing if we didn't match
    }
    Else {
        #Create another blank temporary file which the corrected file contents will be written to
        $tmpFileName_DataCorrection = $file.Name + $tmpExt_DataCorrection
        $tmpFile_DataCorrection = $directoryOfFiles + $tmpFileName_DataCorrection
        New-Item -ItemType File -Path $tmpFile_DataCorrection
        foreach ( $line in $content ) {
            If ( $line.Contains("@")) {
                Add-Content -Path $tmpFile_DataCorrection -Value $line.Replace($stringToReplace,$newString)
                #Counter to know whether any processing was done or not
                $processed++
                }
            Else {
                Add-Content -Path $tmpFile_DataCorrection -Value $line
            }
        }   
        #Backup (rename) the original file, and rename the temp file to be the same name as the original
        Rename-Item -Path $file.FullName -NewName ($file.FullName + $DataCorrectionAppend) -Force -Confirm:$false       
        Move-Item -Path ( $file.FullName + $DataCorrectionAppend ) -Destination backupDir -Force -Confirm:$false
        Rename-Item -Path $tmpFile_DataCorrection -NewName $file.FullName -Force -Confirm:$false

        # Check to see if anything was done, then populate a variable to use in final email alert if there was
        If (!$processed) {
            #no message as did nothing
            }
        Else {
            New-Variable -Name ( "processed" + $file.Name) -Value $strProcessed
            }

    } # Out of If loop
    }

答案 1 :(得分:0)

一方面,您的正则表达式甚至与您要替换的正则表达式都不匹配,因为您在a中逃脱了amount

\b(Total\s\amount\s\$)(\d?\d?\d?...
#         ^^

\a是与{alarm”或“ bell”字符\u0007匹配的escape sequence

此外,如果要计算两个捕获的总和,则需要先将它们转换为数值,否则+运算符只会将两个字符串连接起来。

$Total    = $Match.Groups[2].Value
$Change   = $Match.Groups[4].Value
$Sumtotal = $Total + $Change                  # gives 11.390.21
$Sumtotal = [double]$Total + [double]$Change  # gives 11.6

您需要在定义其他变量之后构建$Result ,否则替换函数将只返回一个空字符串。

更改此:

$RegexPattern = '\b(Total\s\amount\s\$)(\d?\d?\d?\d?\d\.?\d?\d?)(\s\|\sChange\s\$)(\d?\d?\d\.?\d?\d?)\b'
$Substitution = {
    param ($Match)
    $Result = $GP1 + $Sumtotal + $GP3 + $Change
    $GP1 = $Match.Groups[1].Value
    $Total = $Match.Groups[2].Value
    $GP3 = $Match.Groups[3].Value
    $Change = $Match.Groups[4].Value
    $Sumtotal = ($Total + $Change)
    return [string]$Result
}

对此:

$RegexPattern = '\b(Total\samount\s\$)(\d?\d?\d?\d?\d\.?\d?\d?)(\s\|\sChange\s\$)(\d?\d?\d\.?\d?\d?)\b'
$Substitution = {
    Param($Match)
    $GP1 = $Match.Groups[1].Value
    $Total = [double]$Match.Groups[2].Value
    $GP3 = $Match.Groups[3].Value
    $Change = [double]$Match.Groups[4].Value
    $Sumtotal = ($Total + $Change)
    $Result = $GP1 + $Sumtotal + $GP3 + $Change
    return [string]$Result
}

和代码将主要执行您想要的操作。 “最多”,因为它不会将计算出的数字格式化为两位小数。您需要自己做。使用format operator-f)并将替换功能更改为以下形式:

$Substitution = {
    Param($Match)
    $GP1      = $Match.Groups[1].Value
    $Total    = [double]$Match.Groups[2].Value
    $GP3      = $Match.Groups[3].Value
    $Change   = [double]$Match.Groups[4].Value
    $Sumtotal = $Total + $Change
    return ('{0}{1:n2}{2}{3:n2}' -f $GP1, $Sumtotal, $GP3, $Change)
}

作为旁注:子表达式\d?\d?\d?\d?\d\.?\d?\d?可以缩短为\d+(?:\.\d+)?(一个或多个数字,可以选择后面跟一个句点和一个或多个数字),或更确切地说,可以缩短为{ {1}}(一到四位数字,可以选择后面跟一个句点,最多两位数)。