Txitxarro
Txitxarro

Reputation: 25

Format specific Lines in generated Text-File

I'm want to format specific Lines in a .st (text) file which was generated with Powershell.

  1. Load TextSnippet for demonstration use ($TemplateSnippetText)
  2. Replace some Text
  3. Align Text-Lines with ":=", so that all ":=" are in one line (as the $TemplateSnippetText)

I'm struggling with the formating, probably a math-problem...? Could that be done with the String.Format("{0,6} {1,15}) Method?

Desired Output

            diMoveStep_TFRX                         := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                         := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute       := FALSE;
            diMoveStep_TFRX                         := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos1.xEnMove  THEN
                fbAxis_TFRX.i_stPar.stMove          := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition      := stDataProduct.stTFRX.lrPos_PickPos1;
                strPickPos1_TFRX                    := 'PickPos1';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute   := TRUE;
                diMoveStep_TFRX                     := 2;
            END_IF
        2:  // Bewegung ist gestartet

Actual Output

        IF NOT fbAxis_TFRX.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_TFRX                     := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                     := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute       := FALSE;
            diMoveStep_TFRX                     := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos1.xEnMove  THEN
                fbAxis_TFRX.i_stPar.stMove          := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition      := stDataProduct.stTFRX.lrPos_PickPos1;
                strPickPos1_TFRX                        := 'PickPos1';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute   := TRUE;
                diMoveStep_TFRX                     := 2;
            END_IF
        2:  // Bewegung ist gestartet

Full Powershell 5.1 Code:

$TemplateSnippetText = 
"ACTION ActAuto_Move_AXISNAME_TARGETPOS: // COMMENT
    // Rücksetzen
    IF NOT stStep.xEntryDone THEN
        IF NOT fbAxis_AXISNAME.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_AXISNAME                             := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_AXISNAME                             := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_AXISNAME OF
        0:  // Bewegung vorbereiten
            fbAxis_AXISNAME.i_stCmd.xMoveAbsolute           := FALSE;
            diMoveStep_AXISNAME                             := 1;
        1:  // Bewegung starten
            IF stPos.stAXISNAME.stTARGETPOS.xEnMove THEN
                fbAxis_AXISNAME.i_stPar.stMove              := stMovePar_AXISNAME;
                fbAxis_AXISNAME.i_stPar.lrPosition          := stDataProduct.stAXISNAME.lrPos_TARGETPOS;
                strTargetPos_AXISNAME                       := 'TARGETPOS';
                fbAxis_AXISNAME.i_stCmd.xMoveAbsolute       := TRUE;
                diMoveStep_AXISNAME                         := 2;
            END_IF
        2:  // Bewegung ist gestartet
            IF fbAxis_AXISNAME.q_stStat.xMoveDone AND
                stPos.stAXISNAME.stTARGETPOS.xInRange THEN
                fbAxis_AXISNAME.i_stCmd.xMoveAbsolute       := FALSE;
                stStep.xActDone                             := TRUE;
                diMoveStep_AXISNAME                         := 3;
            END_IF
        3:  // Bewegung ist beStringEndt 
            ;
    END_CASE
    
    // Stop deaktivieren während der Bewegung
    stStep.enStopMode                                       := SEL(fbAxis_AXISNAME.i_stCmd.xMoveAbsolute, EnableStop, DisableStop);
END_ACTION

"
#Dateipfad
$strFilePath = 'C:\Temp\CodeSnippet.st' 
$RegPatRepWhiteSpaces = '\s+?(?=:=)'    # https://regex101.com/r/IEiymN/1
$RegPatStartOfString = '^.*?(?=:=)'     # https://regex101.com/r/icJGAy/1
$RegPatEndOfString  = ':=(.*)'          # https://regex101.com/r/0UlzT7/1


# File-Inhalt löschen
Remove-Item $strFilePath  -Include *.st

$SnippetsToGenerate = @(
    [PSCustomObject]@{COMMENT = 'Zielposition1'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos1' }
   # [PSCustomObject]@{COMMENT = 'Zielposition2'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos2' }
    #[PSCustomObject]@{COMMENT = 'Zielposition3'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos3' }
)

$SnippetsToGenerate | ForEach-Object {
$CurrentSnippet = $TemplateSnippetText
$CurrentSnippet = $CurrentSnippet -replace "COMMENT", $_.COMMENT -replace "AXISNAME", $_.AXISNAME -replace "TARGETPOS", $_.TARGETPOS
$CurrentSnippet | Out-File -FilePath $strFilePath -Append 
} 

    (Get-Content -Path $strFilePath -Raw) -Replace $RegPatRepWhiteSpaces,'' | Set-Content -Path $strFilePath
    
    $IndexOfAllocation = Get-Content -Path $strFilePath | ForEach-Object {$_.IndexOf(":=") } | Measure-Object -Maximum
    
    (Get-Content -Path $strFilePath) | ForEach-Object {
            $currentObject = $_
            if($currentObject -match ':='){   
                $StringStart = [Regex]::Matches($currentObject, $RegPatStartOfString).Value 
                $StringEnd = [Regex]::Matches($currentObject, $RegPatEndOfString ).Value

                Write-Host "Lenght StringStart" $StringStart.Length"Lenght StringEnd" $StringEnd.Length
                Write-host "Max" $IndexOfAllocation.Maximum

                [uint32]$DiffToPaddAbsolute = ($IndexOfAllocation.Maximum  - $StringStart.Length)
        
                #if (($DiffToPaddAbsolute % 4) -gt 2) {
                    $DiffToPaddAbsoluteTabs = [math]::Ceiling($DiffToPaddAbsolute / 4) + 1
                #   } else {
                    #$DiffToPaddAbsoluteTabs = [math]::Floor($DiffToPaddAbsolute / 4) + 1
                #}
                $StringStartPadded= $StringStart.PadRight($StringStart.Length + $DiffToPaddAbsoluteTabs,[char]9)
                $currentObject = "$StringStartPadded$StringEnd"
                }
            $currentObject
    } | Set-Content  -Path $strFilePath
Invoke-Item $strFilePath

Upvotes: 1

Views: 176

Answers (2)

Txitxarro
Txitxarro

Reputation: 25

Thanks again Mathias for helping me out with this. Had to change a few more things:

$FilePath = "C:\Temp\CodeSnippet.st"
$RegPatRepWhiteSpaces = '\s+?(?=:=)'    # https://regex101.com/r/IEiymN/1
[uint16]$SpacesPerTab = 4
$SpacesPerTabAsString = [string]::new([char]32, $SpacesPerTab)
$TemplateSnippetText = 
"
ACTION Svd_NAME : // Schutzverdeck: COMMENT
    stHw.stBasic.stSvd_AXISNAME.stIn.xProtCircleIsClosedAndLocked   := xReplaceMe;
    stHw.stBasic.stSvd_AXISNAME.stIn.xAreaRdyForSvd             := xRepalaceMe;
    fbSvd_AXISNAME.i_stIoMap                                    := stHw.stBasic.stSvd_AXISNAME.stIn; 
    fbSvd_AXISNAME.i_udiVisu                                        := ADR(stVisu.stBasic.stSvd_AXISNAME); 
    fbSvd_AXISNAME();
    stHw.stBasic.stSvd_AXISNAMEstOut                        := fbSvd_AXISNAME.q_stIoMap;
    xReplaceMe                                                      := fbSvd_AXISNAME.q_stStat.xRequest;
END_ACTION
"

$SnippetsToGenerate = @(
  [PSCustomObject]@{COMMENT = 'ZielpositionMitEinerLaenge'; AXISNAME = 'LangeraAcnName'; TARGETPOS = 'PickPos1' }
  [PSCustomObject]@{COMMENT = 'Zielposition2'; AXISNAME = 'EinNochViiisiiiiiiiiiiiiiielLaengereAchsenName'; TARGETPOS = 'PickPos2' }
  [PSCustomObject]@{COMMENT = 'Zielposidaassdtion3'; AXISNAME = 'TFRaaassdX'; TARGETPOS = 'PicdkPos3' }
)

$SnippetsToGenerate | ForEach-Object {
  # Use `-creplace` (Case-sensitive replace)
  $snippet = $TemplateSnippetText -creplace 'COMMENT', $_.COMMENT -creplace 'AXISNAME', $_.AXISNAME -creplace 'TARGETPOS', $_.TARGETPOS 

  # Replace all Tabs with Spaces to keep calculation simple
  $snippet =  $snippet -replace [char]9, $SpacesPerTabAsString -replace $RegPatRepWhiteSpaces, ''

  # Split into individual lines
  $lines = $snippet -split '\r?\n'
  
  # Use String.IndexOf() to find the current column offset of `:=` in each line
  $offsets = $lines | ForEach-Object IndexOf ':='
  
  # Sort the offsets to find the right-most occurrence (we will align everything to this one)
  $targetOffset = $offsets | Sort-Object -Descending | Select-Object -First 1

  # Round the offset to the next number divisible by SpacesPerTab, then add one more tab
  $targetOffset += ($targetOffset % $SpacesPerTab) + $SpacesPerTab

  for ($i = 0; $i -lt $lines.Count; $i++) {
    $line = $lines[$i]
    $offset = $offsets[$i]

    # $offset is > -1, so we know the line contains a `:=`
    if ($offset -in 0..$targetOffset) {

        # Calculate the number of Spaces that we want to insert
        $SpacesToInsert = ($targetOffset - $offset) % $SpacesPerTab

        # Calculate the number of Tabs that we want to insert (after filling with Spaces)
        $TabsToInsert = ($targetOffset - $offset - $SpacesToInsert) / $SpacesPerTab

        # First inserting the required number of spaces at the position right in front of `:=` and after fill up with Tabs
        $lines[$i] = $line.Insert($offset, [string]::new(" ", $SpacesToInsert)).Insert($offset + $SpacesToInsert, [string]::new([char]9, $TabsToInsert ))
      }
  }
  # Output, Replace all Groups of Spaces with Tabs
  $lines -replace  $SpacesPerTabAsString, [char]9  
} |Set-Content $FilePath

Invoke-Item "C:\Temp\CodeSnippet.st"

Upvotes: 0

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174505

I think you might be over-complicating the padding - regex is not required at all, we just need to find the offset at which := occurs in each line after the initial replacement:

$FilePath = "C:\Temp\CodeSnippet.st"
$TemplateSnippetText = "<Insert Your Template Here>"

$SnippetsToGenerate = @(
  [PSCustomObject]@{COMMENT = 'Zielposition1'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos1' }
  [PSCustomObject]@{COMMENT = 'Zielposition2'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos2' }
  [PSCustomObject]@{COMMENT = 'Zielposition3'; AXISNAME = 'TFRX'; TARGETPOS = 'PickPos3' }
)

$SnippetsToGenerate | ForEach-Object {
  # Use `-creplace` (Case-sensitive replace)
  $snippet = $TemplateSnippetText -creplace 'COMMENT', $_.COMMENT -creplace 'AXISNAME', $_.AXISNAME -creplace 'TARGETPOS', $_.TARGETPOS

  # Split into individual lines
  $lines = $snippet -split '\r?\n'
  
  # Use String.IndexOf() to find the current column offset of `:=` in each line
  $offsets = $lines | ForEach-Object IndexOf ':='
  
  # Sort the offsets to find the right-most occurrence (we will align everything to this one)
  $targetOffset = $offsets | Sort-Object -Descending | Select-Object -First 1
  
  for ($i = 0; $i -lt $lines.Count; $i++) {
    $line = $lines[$i]
    $offset = $offsets[$i]
  
    if ($offset -in 0..$targetOffset) {
      # $offset is > -1, so we know the line contains a `:=`, let's left-pad it by 
      # inserting the required number of spaces at the position right in front of `:=`
      $lines[$i] = $line.Insert($offset, [string]::new(" ", $targetOffset - $offset))
    }
  }

  # Output 
  $lines
} |Set-Content $FilePath

Which, with the template provided in your question, gives me the following output in CodeSnippet.st:

ACTION ActAuto_Move_TFRX_PickPos1: // Zielposition1
    // Rücksetzen
    IF NOT stStep.xEntryDone THEN
        IF NOT fbAxis_TFRX.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_TFRX                                 := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                                 := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute               := FALSE;
            diMoveStep_TFRX                                 := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos1.xEnMove THEN
                fbAxis_TFRX.i_stPar.stMove                  := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition              := stDataProduct.stTFRX.lrPos_PickPos1;
                strTargetPos_TFRX                           := 'PickPos1';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := TRUE;
                diMoveStep_TFRX                             := 2;
            END_IF
        2:  // Bewegung ist gestartet
            IF fbAxis_TFRX.q_stStat.xMoveDone AND
                stPos.stTFRX.stPickPos1.xInRange THEN
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := FALSE;
                stStep.xActDone                             := TRUE;
                diMoveStep_TFRX                             := 3;
            END_IF
        3:  // Bewegung ist beStringEndt 
            ;
    END_CASE
    
    // Stop deaktivieren während der Bewegung
    stStep.enStopMode                                       := SEL(fbAxis_TFRX.i_stCmd.xMoveAbsolute, EnableStop, DisableStop);
END_ACTION

ACTION ActAuto_Move_TFRX_PickPos2: // Zielposition2
    // Rücksetzen
    IF NOT stStep.xEntryDone THEN
        IF NOT fbAxis_TFRX.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_TFRX                                 := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                                 := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute               := FALSE;
            diMoveStep_TFRX                                 := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos2.xEnMove THEN
                fbAxis_TFRX.i_stPar.stMove                  := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition              := stDataProduct.stTFRX.lrPos_PickPos2;
                strTargetPos_TFRX                           := 'PickPos2';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := TRUE;
                diMoveStep_TFRX                             := 2;
            END_IF
        2:  // Bewegung ist gestartet
            IF fbAxis_TFRX.q_stStat.xMoveDone AND
                stPos.stTFRX.stPickPos2.xInRange THEN
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := FALSE;
                stStep.xActDone                             := TRUE;
                diMoveStep_TFRX                             := 3;
            END_IF
        3:  // Bewegung ist beStringEndt 
            ;
    END_CASE
    
    // Stop deaktivieren während der Bewegung
    stStep.enStopMode                                       := SEL(fbAxis_TFRX.i_stCmd.xMoveAbsolute, EnableStop, DisableStop);
END_ACTION

ACTION ActAuto_Move_TFRX_PickPos3: // Zielposition3
    // Rücksetzen
    IF NOT stStep.xEntryDone THEN
        IF NOT fbAxis_TFRX.i_stCmd.xMoveAbsolute THEN   // Bewegung starten
            diMoveStep_TFRX                                 := 1;
        ELSE // Bewegung vorbereiten
            diMoveStep_TFRX                                 := 0;
        END_IF
    END_IF

    // Schrittkette Bewegung
    CASE diMoveStep_TFRX OF
        0:  // Bewegung vorbereiten
            fbAxis_TFRX.i_stCmd.xMoveAbsolute               := FALSE;
            diMoveStep_TFRX                                 := 1;
        1:  // Bewegung starten
            IF stPos.stTFRX.stPickPos3.xEnMove THEN
                fbAxis_TFRX.i_stPar.stMove                  := stMovePar_TFRX;
                fbAxis_TFRX.i_stPar.lrPosition              := stDataProduct.stTFRX.lrPos_PickPos3;
                strTargetPos_TFRX                           := 'PickPos3';
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := TRUE;
                diMoveStep_TFRX                             := 2;
            END_IF
        2:  // Bewegung ist gestartet
            IF fbAxis_TFRX.q_stStat.xMoveDone AND
                stPos.stTFRX.stPickPos3.xInRange THEN
                fbAxis_TFRX.i_stCmd.xMoveAbsolute           := FALSE;
                stStep.xActDone                             := TRUE;
                diMoveStep_TFRX                             := 3;
            END_IF
        3:  // Bewegung ist beStringEndt 
            ;
    END_CASE
    
    // Stop deaktivieren während der Bewegung
    stStep.enStopMode                                       := SEL(fbAxis_TFRX.i_stCmd.xMoveAbsolute, EnableStop, DisableStop);
END_ACTION

If you want to retain the original offset simply calculate the $targetOffset based on the template without making any replacements, before generating the actual snippets:

$targetOffset = $TemplateSnippetText -replace '\r?\n' |ForEach-Object IndexOf := |Sort-Object -Descending |Select-Object -First 1

$SnippetsToGenerate | ForEach-Object {
   # ...

Upvotes: 1

Related Questions