Добавьте значения группы захвата в цикл замены PowerShell - PullRequest
0 голосов
/ 16 сентября 2018

Необходимость замены строки в нескольких текстовых файлах на одну и ту же строку, за исключением случаев, когда группа захвата 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 голосов
/ 16 сентября 2018

Во-первых, ваше регулярное выражение даже не соответствует тому, что вы пытаетесь заменить, потому что вы избежали a в amount:

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

\a - это escape-последовательность , которая соответствует символу "будильник" или "звонок" \u0007.

Кроме того, если вы хотите вычислить сумму двух захватов, вам необходимо сначала преобразовать их в числовые значения, в противном случае оператор + просто объединит две строки.

$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(<b><i>Total\s\amount</i></b>\s\$)(\d?\d?\d?\d?\d\.?\d?\d?)(\s\|\sChange\s\$)(\d?\d?\d\.?\d?\d?)\b'
$Substitution = {
    param ($Match)
    <b><i>$Result = $GP1 + $Sumtotal + $GP3 + $Change</i></b>
    $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(<b><i>Total\samount</i></b>\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)
    <b><i>$Result = $GP1 + $Sumtotal + $GP3 + $Change</i></b>
    return [string]$Result
}

и код будет в основном делать то, что вы хотите. «В основном», потому что он не будет форматировать вычисленное число до двойных десятичных знаков. Вы должны сделать это самостоятельно. Используйте оператор формата (-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+)? (одна или несколько цифр, необязательно с точкой и одной или несколькими цифрами) или, точнее, до \d{1,4}(?:\.\d{0,2})? (одно до четырех цифр, необязательно с точкой и до 2 цифр).

0 голосов
/ 16 сентября 2018

вот как я это сделаю: это извлечено из более крупного скрипта, который регулярно сканирует каталог на наличие файлов, затем выполняет аналогичные манипуляции, и я быстро изменил переменные, чтобы запутать их, так что кричите, если это не такработать, а завтра я расскажу более подробно.

Он также создает резервную копию каждого файла и работает с временной копией перед переименованием.

Обратите внимание, что он также отправляет оповещение по электронной почте(код в конце), чтобы сказать, была ли выполнена какая-либо обработка - это потому, что она предназначена для выполнения как запланированная задача в исходной

$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
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...