Dafsio
Dafsio

Reputation: 23

Changing multiple lines in a text file based on a psobject

I'm working on a script which will add some additional informations to a txt file. These informations are stored in a CSV file which looks like this (the data will differs each time the script will launch):

Number;A;B;ValueOfB
FP01340/05/20;0;1;GTU_01,GTU_03
FP01342/05/20;1;0;GTU01

The txt file looks like this (data inside will of course differ each time):

1|1|FP01340/05/20|2020-05-02|2020-05-02|2020-05-02|166,91|203,23|36,32|nothing interesting 18|33333|63-111 somewhere|||||
2|zwol|9,00|9,00|0,00
2|23|157,91|194,23|36,32
1|1|FP01341/05/20|2020-05-02|2020-05-02|2020-05-02|12,19|14,99|2,80|Some info |2222222|blabla|11-111 something||||
2|23|12,19|14,99|2,80
1|1|FP01342/05/20|2020-05-02|2020-05-02|2020-05-02|525,36|589,64|64,28|bla|222222|blba 36||62030|something||
2|5|213,93|224,63|10,70
2|8|120,34|129,97|9,63
2|23|191,09|235,04|43,95

What I need to do is to find a line which contains 'Number' and then add value 'A' and 'B' from a CSV in a form: |0|1 and then on the first line below, at the end, add 'ValueofB' in a form |AAA_01,AAA_03

So the first two lines should look like this at the end:

1|1|FP01340/05/20|2020-05-02|2020-05-02|2020-05-02|166,91|203,23|36,32|nothing interesting 18|33333|63-111 somewhere||||||0|1
2|zwol|9,00|9,00|0,00|AAA_01,AAA_03
2|23|157,91|194,23|36,32

Rest of lines should not be touched.

I made a script which uses select-string method with context to find what I need to - put that into an object and then add to previously found strings what I need to and put that in to an another object.

My script is as follws:

$csvFile = Import-Csv -Path Somepath\file.csv -Delimiter ";"
$file = "Somepath2\SomeName.txt"

$LinesToChange = @()
$script:LinesToChange = $LinesToChange
$LinesOriginal = @()
$script:LinesOriginal = $LinesOriginal

foreach ($line in $csvFile) {

    Select-String -Path $file -Pattern "$($Line.number)" -Encoding default -Context 0, 1 | ForEach-Object {
        $1 = $_.Line
        $2 = $_.Context.PostContext
    }

$ListOrg = [pscustomobject]@{
    Line_org     = $1
    Line_GTU_org = $2
}
$LinesOriginal = $LinesOriginal + $ListOrg

$lineNew = $ListOrg.Line_org | foreach { $_ + "|$($line.A)|$($line.B)" }
$GTUNew = $ListOrg.Line_GTU_org | foreach { $_ + "|$($line.ValueofB)" }

$ListNew = [pscustomobject]@{
    Line_new     = $lineNew
    Line_GTU_new = $GTUNew
    Line_org     = $ListOrg.Line_org
    Line_GTU_org = $ListOrg.Line_GTU_org
}

$LinesToChange = $LinesToChange + $ListNew

} 

The output is an object $LinesToChange which have original lines and lines after the change. The issue is I have no idea how to use that to change the txt file. I tried few methods and ended up with file which contains updated lines but all others are doubbled (I tried foreach) or PS is using whole RAM and couldn't finish the job :)

My latest idea is to use something like that:

(Get-Content -Path $file) | ForEach-Object {
    $line = $_
    $LinesToChange.GetEnumerator() | ForEach-Object {
        if ($line -match "$($LinesToChange.Line_org)") {
            $line = $line -replace "$($LinesToChange.Line_org)", "$($LinesToChange.Line_new)"

        }
        if ($line -match "$($LinesToChange.Line_GTU_org)") {
            $line = $line -replace "$($LinesToChange.Line_GTU_org)", "$($LinesToChange.Line_GTU_new)"

        }
    }
} | Set-Content -Path Somehere\newfile.txt

It seemed promising at first, but the variable $line contains all lines and as such it can't find the match.

Also I need to be sure that the second line will be directly below the first one (it is unlikely but it can be a case that there will be two or more lines with the same data while the "number" from CSV file is unique) so preferably while changing the txt file it would be needed to find a match for a two-liner; in short:

find this two lines:

1|1|FP01340/05/20|2020-05-02|2020-05-02|2020-05-02|166,91|203,23|36,32|nothing interesting 18|33333|63-111 somewhere|||||
2|zwol|9,00|9,00|0,00

change them to:

1|1|FP01340/05/20|2020-05-02|2020-05-02|2020-05-02|166,91|203,23|36,32|nothing interesting 18|33333|63-111 somewhere||||||0|1
2|zwol|9,00|9,00|0,00|AAA_01,AAA_03

Do that for all lines in a $LinesToChange

Any help will be much appreciated!

Greetings!

Upvotes: 0

Views: 272

Answers (1)

Theo
Theo

Reputation: 61068

Some strange text file you have there, but anyway, this should do it:

# read in the text file as string array
$txt = Get-Content -Path '<PathToTheTextFile>'
$csv = Import-Csv -Path '<PathToTheCSVFile>' -Delimiter ';'

# loop through the items (rows) in the CSV and find matching lines in the text array
foreach ($item in $csv) {
    $match = $txt | Select-String -Pattern ('|{0}|' -f $item.Number) -SimpleMatch
    if ($match) {
        # update the matching text line (array indices count from 0, so we do -1)
        $txt[$match.LineNumber -1] += ('|{0}|{1}' -f $item.A, $item.B)
        # update the line following
        $txt[$match.LineNumber] += ('|{0}' -f $item.ValueOfB)
    }
}

# show updated text on screen
$txt

# save updated text to file
$txt | Set-Content -Path 'Somehere\newfile.txt'

Upvotes: 1

Related Questions