Требуется заменить строку в нескольких текстовых файлах одной и той же строкой, за исключением того, что группа захвата 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
}
0
I-Script-Alot 16 Сен 2018 в 09:58

2 ответа

Лучший ответ

Во-первых, ваше регулярное выражение даже не соответствует тому, что вы пытаетесь заменить, потому что вы экранировали 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(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
}

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

0
Ansgar Wiechers 20 Сен 2018 в 07:18

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

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

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

$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
    }
0
Ian Manning 16 Сен 2018 в 10:43